evolution-3.6.4/widgets/table/e-table-field-chooser-item.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Chris Lahey <clahey@ximian.com>
 18  *
 19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 20  *
 21  */
 22 
 23 #ifdef HAVE_CONFIG_H
 24 #include <config.h>
 25 #endif
 26 
 27 #include <string.h>
 28 
 29 #include <gtk/gtk.h>
 30 #include <libgnomecanvas/libgnomecanvas.h>
 31 #include <gdk-pixbuf/gdk-pixbuf.h>
 32 
 33 #include <glib/gi18n.h>
 34 #include "e-util/e-util.h"
 35 #include "libevolution-utils/e-xml-utils.h"
 36 #include "misc/e-canvas.h"
 37 
 38 #include "e-table-col-dnd.h"
 39 #include "e-table-defines.h"
 40 #include "e-table-field-chooser-item.h"
 41 #include "e-table-header-utils.h"
 42 #include "e-table-header.h"
 43 
 44 #define d(x)
 45 
 46 #if 0
 47 enum {
 48 	BUTTON_PRESSED,
 49 	LAST_SIGNAL
 50 };
 51 
 52 static guint etfci_signals[LAST_SIGNAL] = { 0, };
 53 #endif
 54 
 55 /* workaround for avoiding API breakage */
 56 #define etfci_get_type e_table_field_chooser_item_get_type
 57 G_DEFINE_TYPE (ETableFieldChooserItem, etfci, GNOME_TYPE_CANVAS_ITEM)
 58 
 59 static void etfci_drop_table_header (ETableFieldChooserItem *etfci);
 60 static void etfci_drop_full_header (ETableFieldChooserItem *etfci);
 61 
 62 enum {
 63 	PROP_0,
 64 	PROP_FULL_HEADER,
 65 	PROP_HEADER,
 66 	PROP_DND_CODE,
 67 	PROP_WIDTH,
 68 	PROP_HEIGHT
 69 };
 70 
 71 static void
 72 etfci_dispose (GObject *object)
 73 {
 74 	ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (object);
 75 
 76 	etfci_drop_table_header (etfci);
 77 	etfci_drop_full_header (etfci);
 78 
 79 	if (etfci->combined_header)
 80 		g_object_unref (etfci->combined_header);
 81 	etfci->combined_header = NULL;
 82 
 83 	if (etfci->font_desc)
 84 		pango_font_description_free (etfci->font_desc);
 85 	etfci->font_desc = NULL;
 86 
 87 	/* Chain up to parent's dispose() method. */
 88 	G_OBJECT_CLASS (etfci_parent_class)->dispose (object);
 89 }
 90 
 91 static gint
 92 etfci_find_button (ETableFieldChooserItem *etfci,
 93                    gdouble loc)
 94 {
 95 	gint i;
 96 	gint count;
 97 	gdouble height = 0;
 98 
 99 	count = e_table_header_count (etfci->combined_header);
100 	for (i = 0; i < count; i++) {
101 		ETableCol *ecol;
102 
103 		ecol = e_table_header_get_column (etfci->combined_header, i);
104 		if (ecol->disabled)
105 			continue;
106 		height += e_table_header_compute_height (
107 			ecol, GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas));
108 		if (height > loc)
109 			return i;
110 	}
111 	return MAX (0, count - 1);
112 }
113 
114 static void
115 etfci_rebuild_combined (ETableFieldChooserItem *etfci)
116 {
117 	gint count;
118 	GHashTable *hash;
119 	gint i;
120 
121 	if (etfci->combined_header != NULL)
122 		g_object_unref (etfci->combined_header);
123 
124 	etfci->combined_header = e_table_header_new ();
125 
126 	hash = g_hash_table_new (NULL, NULL);
127 
128 	count = e_table_header_count (etfci->header);
129 	for (i = 0; i < count; i++) {
130 		ETableCol *ecol = e_table_header_get_column (etfci->header, i);
131 		if (ecol->disabled)
132 			continue;
133 		g_hash_table_insert (
134 			hash, GINT_TO_POINTER (ecol->col_idx),
135 			GINT_TO_POINTER (1));
136 	}
137 
138 	count = e_table_header_count (etfci->full_header);
139 	for (i = 0; i < count; i++) {
140 		ETableCol *ecol = e_table_header_get_column (etfci->full_header, i);
141 		if (ecol->disabled)
142 			continue;
143 		if (!(GPOINTER_TO_INT (g_hash_table_lookup (
144 				hash, GINT_TO_POINTER (ecol->col_idx)))))
145 			e_table_header_add_column (etfci->combined_header, ecol, -1);
146 	}
147 
148 	g_hash_table_destroy (hash);
149 }
150 
151 static void
152 etfci_reflow (GnomeCanvasItem *item,
153               gint flags)
154 {
155 	ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
156 	gdouble old_height;
157 	gint i;
158 	gint count;
159 	gdouble height = 0;
160 
161 	etfci_rebuild_combined (etfci);
162 
163 	old_height = etfci->height;
164 
165 	count = e_table_header_count (etfci->combined_header);
166 	for (i = 0; i < count; i++) {
167 		ETableCol *ecol;
168 
169 		ecol = e_table_header_get_column (etfci->combined_header, i);
170 		if (ecol->disabled)
171 			continue;
172 		height += e_table_header_compute_height (
173 			ecol, GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas));
174 	}
175 
176 	etfci->height = height;
177 
178 	if (old_height != etfci->height)
179 		e_canvas_item_request_parent_reflow (item);
180 
181 	gnome_canvas_item_request_update (item);
182 }
183 
184 static void
185 etfci_update (GnomeCanvasItem *item,
186               const cairo_matrix_t *i2c,
187               gint flags)
188 {
189 	ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
190 	gdouble x1, y1, x2, y2;
191 
192 	if (GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->update)
193 		GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->update (
194 			item, i2c, flags);
195 
196 	x1 = y1 = 0;
197 	x2 = etfci->width;
198 	y2 = etfci->height;
199 
200 	gnome_canvas_matrix_transform_rect (i2c, &x1, &y1, &x2, &y2);
201 
202 	if (item->x1 != x1 ||
203 	    item->y1 != y1 ||
204 	    item->x2 != x2 ||
205 	    item->y2 != y2)
206 		{
207 			gnome_canvas_request_redraw (
208 				item->canvas, item->x1,
209 				item->y1, item->x2, item->y2);
210 			item->x1 = x1;
211 			item->y1 = y1;
212 			item->x2 = x2;
213 			item->y2 = y2;
214 /* FIXME: Group Child bounds !? */
215 #if 0
216 			gnome_canvas_group_child_bounds (
217 				GNOME_CANVAS_GROUP (item->parent), item);
218 #endif
219 		}
220 	gnome_canvas_request_redraw (
221 		item->canvas, item->x1, item->y1, item->x2, item->y2);
222 }
223 
224 static void
225 etfci_font_load (ETableFieldChooserItem *etfci)
226 {
227 	GtkWidget *widget;
228 	GtkStyle *style;
229 
230 	if (etfci->font_desc)
231 		pango_font_description_free (etfci->font_desc);
232 
233 	widget = GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas);
234 	style = gtk_widget_get_style (widget);
235 	etfci->font_desc = pango_font_description_copy (style->font_desc);
236 }
237 
238 static void
239 etfci_drop_full_header (ETableFieldChooserItem *etfci)
240 {
241 	GObject *header;
242 
243 	if (!etfci->full_header)
244 		return;
245 
246 	header = G_OBJECT (etfci->full_header);
247 	if (etfci->full_header_structure_change_id)
248 		g_signal_handler_disconnect (
249 			header, etfci->full_header_structure_change_id);
250 	if (etfci->full_header_dimension_change_id)
251 		g_signal_handler_disconnect (
252 			header, etfci->full_header_dimension_change_id);
253 	etfci->full_header_structure_change_id = 0;
254 	etfci->full_header_dimension_change_id = 0;
255 
256 	if (header)
257 		g_object_unref (header);
258 	etfci->full_header = NULL;
259 	etfci->height = 0;
260 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci));
261 }
262 
263 static void
264 full_header_structure_changed (ETableHeader *header,
265                                ETableFieldChooserItem *etfci)
266 {
267 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci));
268 }
269 
270 static void
271 full_header_dimension_changed (ETableHeader *header,
272                                gint col,
273                                ETableFieldChooserItem *etfci)
274 {
275 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci));
276 }
277 
278 static void
279 etfci_add_full_header (ETableFieldChooserItem *etfci,
280                        ETableHeader *header)
281 {
282 	etfci->full_header = header;
283 	g_object_ref (etfci->full_header);
284 
285 	etfci->full_header_structure_change_id = g_signal_connect (
286 		header, "structure_change",
287 		G_CALLBACK (full_header_structure_changed), etfci);
288 	etfci->full_header_dimension_change_id = g_signal_connect (
289 		header, "dimension_change",
290 		G_CALLBACK (full_header_dimension_changed), etfci);
291 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci));
292 }
293 
294 static void
295 etfci_drop_table_header (ETableFieldChooserItem *etfci)
296 {
297 	GObject *header;
298 
299 	if (!etfci->header)
300 		return;
301 
302 	header = G_OBJECT (etfci->header);
303 	if (etfci->table_header_structure_change_id)
304 		g_signal_handler_disconnect (
305 			header, etfci->table_header_structure_change_id);
306 	if (etfci->table_header_dimension_change_id)
307 		g_signal_handler_disconnect (
308 			header, etfci->table_header_dimension_change_id);
309 	etfci->table_header_structure_change_id = 0;
310 	etfci->table_header_dimension_change_id = 0;
311 
312 	if (header)
313 		g_object_unref (header);
314 	etfci->header = NULL;
315 	etfci->height = 0;
316 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci));
317 }
318 
319 static void
320 table_header_structure_changed (ETableHeader *header,
321                                 ETableFieldChooserItem *etfci)
322 {
323 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci));
324 }
325 
326 static void
327 table_header_dimension_changed (ETableHeader *header,
328                                 gint col,
329                                 ETableFieldChooserItem *etfci)
330 {
331 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci));
332 }
333 
334 static void
335 etfci_add_table_header (ETableFieldChooserItem *etfci,
336                         ETableHeader *header)
337 {
338 	etfci->header = header;
339 	g_object_ref (etfci->header);
340 
341 	etfci->table_header_structure_change_id = g_signal_connect (
342 		header, "structure_change",
343 		G_CALLBACK (table_header_structure_changed), etfci);
344 	etfci->table_header_dimension_change_id = g_signal_connect (
345 		header, "dimension_change",
346 		G_CALLBACK (table_header_dimension_changed), etfci);
347 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci));
348 }
349 
350 static void
351 etfci_set_property (GObject *object,
352                     guint property_id,
353                     const GValue *value,
354                     GParamSpec *pspec)
355 {
356 	GnomeCanvasItem *item;
357 	ETableFieldChooserItem *etfci;
358 
359 	item = GNOME_CANVAS_ITEM (object);
360 	etfci = E_TABLE_FIELD_CHOOSER_ITEM (object);
361 
362 	switch (property_id) {
363 	case PROP_FULL_HEADER:
364 		etfci_drop_full_header (etfci);
365 		if (g_value_get_object (value))
366 			etfci_add_full_header (
367 				etfci, E_TABLE_HEADER (
368 				g_value_get_object (value)));
369 		break;
370 
371 	case PROP_HEADER:
372 		etfci_drop_table_header (etfci);
373 		if (g_value_get_object (value))
374 			etfci_add_table_header (
375 				etfci, E_TABLE_HEADER (
376 				g_value_get_object (value)));
377 		break;
378 
379 	case PROP_DND_CODE:
380 		g_free (etfci->dnd_code);
381 		etfci->dnd_code = g_strdup (g_value_get_string (value));
382 		break;
383 
384 	case PROP_WIDTH:
385 		etfci->width = g_value_get_double (value);
386 		gnome_canvas_item_request_update (item);
387 		break;
388 	}
389 }
390 
391 static void
392 etfci_get_property (GObject *object,
393                     guint property_id,
394                     GValue *value,
395                     GParamSpec *pspec)
396 {
397 	ETableFieldChooserItem *etfci;
398 
399 	etfci = E_TABLE_FIELD_CHOOSER_ITEM (object);
400 
401 	switch (property_id) {
402 
403 	case PROP_DND_CODE:
404 		g_value_set_string (value, etfci->dnd_code);
405 		break;
406 	case PROP_WIDTH:
407 		g_value_set_double (value, etfci->width);
408 		break;
409 	case PROP_HEIGHT:
410 		g_value_set_double (value, etfci->height);
411 		break;
412 	default:
413 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
414 		break;
415 	}
416 }
417 
418 static void
419 etfci_drag_data_get (GtkWidget *widget,
420                      GdkDragContext *context,
421                      GtkSelectionData *selection_data,
422                      guint info,
423                      guint time,
424                      ETableFieldChooserItem *etfci)
425 {
426 	if (etfci->drag_col != -1) {
427 		gchar *string = g_strdup_printf ("%d", etfci->drag_col);
428 		gtk_selection_data_set (
429 			selection_data,
430 			GDK_SELECTION_TYPE_STRING,
431 			sizeof (string[0]),
432 			(guchar *) string,
433 			strlen (string));
434 		g_free (string);
435 	}
436 }
437 
438 static void
439 etfci_drag_end (GtkWidget *canvas,
440                 GdkDragContext *context,
441                 ETableFieldChooserItem *etfci)
442 {
443 	etfci->drag_col = -1;
444 }
445 
446 static void
447 etfci_realize (GnomeCanvasItem *item)
448 {
449 	ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
450 
451 	if (GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)-> realize)
452 		(*GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->realize)(item);
453 
454 	if (!etfci->font_desc)
455 		etfci_font_load (etfci);
456 
457 	etfci->drag_end_id = g_signal_connect (
458 		item->canvas, "drag_end",
459 		G_CALLBACK (etfci_drag_end), etfci);
460 	etfci->drag_data_get_id = g_signal_connect (
461 		item->canvas, "drag_data_get",
462 		G_CALLBACK (etfci_drag_data_get), etfci);
463 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci));
464 }
465 
466 static void
467 etfci_unrealize (GnomeCanvasItem *item)
468 {
469 	ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
470 
471 	if (etfci->font_desc)
472 		pango_font_description_free (etfci->font_desc);
473 	etfci->font_desc = NULL;
474 
475 	g_signal_handler_disconnect (item->canvas, etfci->drag_end_id);
476 	etfci->drag_end_id = 0;
477 	g_signal_handler_disconnect (item->canvas, etfci->drag_data_get_id);
478 	etfci->drag_data_get_id = 0;
479 
480 	if (GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->unrealize)
481 		(*GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->unrealize)(item);
482 }
483 
484 static void
485 etfci_draw (GnomeCanvasItem *item,
486             cairo_t *cr,
487             gint x,
488             gint y,
489             gint width,
490             gint height)
491 {
492 	ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
493 	GnomeCanvas *canvas = item->canvas;
494 	gint rows;
495 	gint y1, y2;
496 	gint row;
497 
498 	if (etfci->combined_header == NULL)
499 		return;
500 
501 	rows = e_table_header_count (etfci->combined_header);
502 
503 	y1 = y2 = 0;
504 	for (row = 0; row < rows; row++, y1 = y2) {
505 		ETableCol *ecol;
506 
507 		ecol = e_table_header_get_column (etfci->combined_header, row);
508 
509 		if (ecol->disabled)
510 			continue;
511 
512 		y2 += e_table_header_compute_height (ecol, GTK_WIDGET (canvas));
513 
514 		if (y1 > (y + height))
515 			break;
516 
517 		if (y2 < y)
518 			continue;
519 
520 		cairo_save (cr);
521 
522 		e_table_header_draw_button (
523 			cr, ecol,
524 			GTK_WIDGET (canvas),
525 			-x, y1 - y,
526 			width, height,
527 			etfci->width, y2 - y1,
528 			E_TABLE_COL_ARROW_NONE);
529 
530 		cairo_restore (cr);
531 	}
532 }
533 
534 static GnomeCanvasItem *
535 etfci_point (GnomeCanvasItem *item,
536              gdouble x,
537              gdouble y,
538              gint cx,
539              gint cy)
540 {
541 	return item;
542 }
543 
544 static gboolean
545 etfci_maybe_start_drag (ETableFieldChooserItem *etfci,
546                         gint x,
547                         gint y)
548 {
549 	if (!etfci->maybe_drag)
550 		return FALSE;
551 
552 	if (MAX (abs (etfci->click_x - x),
553 		 abs (etfci->click_y - y)) <= 3)
554 		return FALSE;
555 
556 	return TRUE;
557 }
558 
559 static void
560 etfci_start_drag (ETableFieldChooserItem *etfci,
561                   GdkEvent *event,
562                   gdouble x,
563                   gdouble y)
564 {
565 	GtkWidget *widget = GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas);
566 	GtkTargetList *list;
567 	GdkDragContext *context;
568 	ETableCol *ecol;
569 	cairo_surface_t *cs;
570 	cairo_t *cr;
571 	gint drag_col;
572 	gint button_height;
573 
574 	GtkTargetEntry  etfci_drag_types[] = {
575 		{ (gchar *) TARGET_ETABLE_COL_TYPE, 0, TARGET_ETABLE_COL_HEADER },
576 	};
577 
578 	if (etfci->combined_header == NULL)
579 		return;
580 
581 	drag_col = etfci_find_button (etfci, y);
582 
583 	if (drag_col < 0 || drag_col > e_table_header_count (etfci->combined_header))
584 		return;
585 
586 	ecol = e_table_header_get_column (etfci->combined_header, drag_col);
587 
588 	if (ecol->disabled)
589 		return;
590 
591 	etfci->drag_col = ecol->col_idx;
592 
593 	etfci_drag_types[0].target = g_strdup_printf (
594 		"%s-%s", etfci_drag_types[0].target, etfci->dnd_code);
595 	d (g_print ("etfci - %s\n", etfci_drag_types[0].target));
596 	list = gtk_target_list_new (etfci_drag_types, G_N_ELEMENTS (etfci_drag_types));
597 	context = gtk_drag_begin (widget, list, GDK_ACTION_MOVE, 1, event);
598 	g_free ((gpointer) etfci_drag_types[0].target);
599 
600 	button_height = e_table_header_compute_height (ecol, widget);
601 	cs = cairo_image_surface_create (
602 		CAIRO_FORMAT_ARGB32,
603 		etfci->width, button_height);
604 	cr = cairo_create (cs);
605 
606 	e_table_header_draw_button (
607 		cr, ecol,
608 		widget, 0, 0,
609 		etfci->width, button_height,
610 		etfci->width, button_height,
611 		E_TABLE_COL_ARROW_NONE);
612 
613 	gtk_drag_set_icon_surface (context, cs);
614 
615 	cairo_surface_destroy (cs);
616 	cairo_destroy (cr);
617 	etfci->maybe_drag = FALSE;
618 }
619 
620 /*
621  * Handles the events on the ETableFieldChooserItem
622  */
623 static gint
624 etfci_event (GnomeCanvasItem *item,
625              GdkEvent *e)
626 {
627 	ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item);
628 	GnomeCanvas *canvas = item->canvas;
629 	gint x, y;
630 
631 	switch (e->type) {
632 	case GDK_MOTION_NOTIFY:
633 		gnome_canvas_w2c (canvas, e->motion.x, e->motion.y, &x, &y);
634 
635 		if (etfci_maybe_start_drag (etfci, x, y))
636 			etfci_start_drag (etfci, e, x, y);
637 		break;
638 
639 	case GDK_BUTTON_PRESS:
640 		gnome_canvas_w2c (canvas, e->button.x, e->button.y, &x, &y);
641 
642 		if (e->button.button == 1) {
643 			etfci->click_x = x;
644 			etfci->click_y = y;
645 			etfci->maybe_drag = TRUE;
646 		}
647 		break;
648 
649 	case GDK_BUTTON_RELEASE: {
650 		etfci->maybe_drag = FALSE;
651 		break;
652 	}
653 
654 	default:
655 		return FALSE;
656 	}
657 	return TRUE;
658 }
659 
660 static void
661 etfci_class_init (ETableFieldChooserItemClass *class)
662 {
663 	GnomeCanvasItemClass *item_class = GNOME_CANVAS_ITEM_CLASS (class);
664 	GObjectClass *object_class = G_OBJECT_CLASS (class);
665 
666 	object_class->dispose = etfci_dispose;
667 	object_class->set_property = etfci_set_property;
668 	object_class->get_property = etfci_get_property;
669 
670 	item_class->update      = etfci_update;
671 	item_class->realize     = etfci_realize;
672 	item_class->unrealize   = etfci_unrealize;
673 	item_class->draw        = etfci_draw;
674 	item_class->point       = etfci_point;
675 	item_class->event       = etfci_event;
676 
677 	g_object_class_install_property (
678 		object_class,
679 		PROP_DND_CODE,
680 		g_param_spec_string (
681 			"dnd_code",
682 			"DnD code",
683 			NULL,
684 			NULL,
685 			G_PARAM_READWRITE));
686 
687 	g_object_class_install_property (
688 		object_class,
689 		PROP_FULL_HEADER,
690 		g_param_spec_object (
691 			"full_header",
692 			"Full Header",
693 			NULL,
694 			E_TYPE_TABLE_HEADER,
695 			G_PARAM_READWRITE));
696 
697 	g_object_class_install_property (
698 		object_class,
699 		PROP_HEADER,
700 		g_param_spec_object (
701 			"header",
702 			"Header",
703 			NULL,
704 			E_TYPE_TABLE_HEADER,
705 			G_PARAM_READWRITE));
706 
707 	g_object_class_install_property (
708 		object_class,
709 		PROP_WIDTH,
710 		g_param_spec_double (
711 			"width",
712 			"Width",
713 			NULL,
714 			0, G_MAXDOUBLE, 0,
715 			G_PARAM_READWRITE));
716 
717 	g_object_class_install_property (
718 		object_class,
719 		PROP_HEIGHT,
720 		g_param_spec_double (
721 			"height",
722 			"Height",
723 			NULL,
724 			0, G_MAXDOUBLE, 0,
725 			G_PARAM_READABLE));
726 }
727 
728 static void
729 etfci_init (ETableFieldChooserItem *etfci)
730 {
731 	etfci->full_header = NULL;
732 	etfci->header = NULL;
733 	etfci->combined_header = NULL;
734 
735 	etfci->height = etfci->width = 0;
736 
737 	etfci->font_desc = NULL;
738 
739 	etfci->full_header_structure_change_id = 0;
740 	etfci->full_header_dimension_change_id = 0;
741 	etfci->table_header_structure_change_id = 0;
742 	etfci->table_header_dimension_change_id = 0;
743 
744 	etfci->dnd_code = NULL;
745 
746 	etfci->maybe_drag = 0;
747 	etfci->drag_end_id = 0;
748 
749 	e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM (etfci), etfci_reflow);
750 }