diff options
Diffstat (limited to 'e-util/e-table-field-chooser-item.c')
-rw-r--r-- | e-util/e-table-field-chooser-item.c | 749 |
1 files changed, 749 insertions, 0 deletions
diff --git a/e-util/e-table-field-chooser-item.c b/e-util/e-table-field-chooser-item.c new file mode 100644 index 0000000000..f72e059f20 --- /dev/null +++ b/e-util/e-table-field-chooser-item.c @@ -0,0 +1,749 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * Chris Lahey <clahey@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> + +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <libgnomecanvas/libgnomecanvas.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "e-canvas.h" +#include "e-table-col-dnd.h" +#include "e-table-defines.h" +#include "e-table-field-chooser-item.h" +#include "e-table-header-utils.h" +#include "e-table-header.h" +#include "e-xml-utils.h" + +#define d(x) + +#if 0 +enum { + BUTTON_PRESSED, + LAST_SIGNAL +}; + +static guint etfci_signals[LAST_SIGNAL] = { 0, }; +#endif + +/* workaround for avoiding API breakage */ +#define etfci_get_type e_table_field_chooser_item_get_type +G_DEFINE_TYPE (ETableFieldChooserItem, etfci, GNOME_TYPE_CANVAS_ITEM) + +static void etfci_drop_table_header (ETableFieldChooserItem *etfci); +static void etfci_drop_full_header (ETableFieldChooserItem *etfci); + +enum { + PROP_0, + PROP_FULL_HEADER, + PROP_HEADER, + PROP_DND_CODE, + PROP_WIDTH, + PROP_HEIGHT +}; + +static void +etfci_dispose (GObject *object) +{ + ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (object); + + etfci_drop_table_header (etfci); + etfci_drop_full_header (etfci); + + if (etfci->combined_header) + g_object_unref (etfci->combined_header); + etfci->combined_header = NULL; + + if (etfci->font_desc) + pango_font_description_free (etfci->font_desc); + etfci->font_desc = NULL; + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (etfci_parent_class)->dispose (object); +} + +static gint +etfci_find_button (ETableFieldChooserItem *etfci, + gdouble loc) +{ + gint i; + gint count; + gdouble height = 0; + + count = e_table_header_count (etfci->combined_header); + for (i = 0; i < count; i++) { + ETableCol *ecol; + + ecol = e_table_header_get_column (etfci->combined_header, i); + if (ecol->disabled) + continue; + height += e_table_header_compute_height ( + ecol, GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas)); + if (height > loc) + return i; + } + return MAX (0, count - 1); +} + +static void +etfci_rebuild_combined (ETableFieldChooserItem *etfci) +{ + gint count; + GHashTable *hash; + gint i; + + if (etfci->combined_header != NULL) + g_object_unref (etfci->combined_header); + + etfci->combined_header = e_table_header_new (); + + hash = g_hash_table_new (NULL, NULL); + + count = e_table_header_count (etfci->header); + for (i = 0; i < count; i++) { + ETableCol *ecol = e_table_header_get_column (etfci->header, i); + if (ecol->disabled) + continue; + g_hash_table_insert ( + hash, GINT_TO_POINTER (ecol->col_idx), + GINT_TO_POINTER (1)); + } + + count = e_table_header_count (etfci->full_header); + for (i = 0; i < count; i++) { + ETableCol *ecol = e_table_header_get_column (etfci->full_header, i); + if (ecol->disabled) + continue; + if (!(GPOINTER_TO_INT (g_hash_table_lookup ( + hash, GINT_TO_POINTER (ecol->col_idx))))) + e_table_header_add_column (etfci->combined_header, ecol, -1); + } + + g_hash_table_destroy (hash); +} + +static void +etfci_reflow (GnomeCanvasItem *item, + gint flags) +{ + ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item); + gdouble old_height; + gint i; + gint count; + gdouble height = 0; + + etfci_rebuild_combined (etfci); + + old_height = etfci->height; + + count = e_table_header_count (etfci->combined_header); + for (i = 0; i < count; i++) { + ETableCol *ecol; + + ecol = e_table_header_get_column (etfci->combined_header, i); + if (ecol->disabled) + continue; + height += e_table_header_compute_height ( + ecol, GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas)); + } + + etfci->height = height; + + if (old_height != etfci->height) + e_canvas_item_request_parent_reflow (item); + + gnome_canvas_item_request_update (item); +} + +static void +etfci_update (GnomeCanvasItem *item, + const cairo_matrix_t *i2c, + gint flags) +{ + ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item); + gdouble x1, y1, x2, y2; + + if (GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->update) + GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->update ( + item, i2c, flags); + + x1 = y1 = 0; + x2 = etfci->width; + y2 = etfci->height; + + gnome_canvas_matrix_transform_rect (i2c, &x1, &y1, &x2, &y2); + + if (item->x1 != x1 || + item->y1 != y1 || + item->x2 != x2 || + item->y2 != y2) + { + gnome_canvas_request_redraw ( + item->canvas, item->x1, + item->y1, item->x2, item->y2); + item->x1 = x1; + item->y1 = y1; + item->x2 = x2; + item->y2 = y2; +/* FIXME: Group Child bounds !? */ +#if 0 + gnome_canvas_group_child_bounds ( + GNOME_CANVAS_GROUP (item->parent), item); +#endif + } + gnome_canvas_request_redraw ( + item->canvas, item->x1, item->y1, item->x2, item->y2); +} + +static void +etfci_font_load (ETableFieldChooserItem *etfci) +{ + GtkWidget *widget; + GtkStyle *style; + + if (etfci->font_desc) + pango_font_description_free (etfci->font_desc); + + widget = GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas); + style = gtk_widget_get_style (widget); + etfci->font_desc = pango_font_description_copy (style->font_desc); +} + +static void +etfci_drop_full_header (ETableFieldChooserItem *etfci) +{ + GObject *header; + + if (!etfci->full_header) + return; + + header = G_OBJECT (etfci->full_header); + if (etfci->full_header_structure_change_id) + g_signal_handler_disconnect ( + header, etfci->full_header_structure_change_id); + if (etfci->full_header_dimension_change_id) + g_signal_handler_disconnect ( + header, etfci->full_header_dimension_change_id); + etfci->full_header_structure_change_id = 0; + etfci->full_header_dimension_change_id = 0; + + if (header) + g_object_unref (header); + etfci->full_header = NULL; + etfci->height = 0; + e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci)); +} + +static void +full_header_structure_changed (ETableHeader *header, + ETableFieldChooserItem *etfci) +{ + e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci)); +} + +static void +full_header_dimension_changed (ETableHeader *header, + gint col, + ETableFieldChooserItem *etfci) +{ + e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci)); +} + +static void +etfci_add_full_header (ETableFieldChooserItem *etfci, + ETableHeader *header) +{ + etfci->full_header = header; + g_object_ref (etfci->full_header); + + etfci->full_header_structure_change_id = g_signal_connect ( + header, "structure_change", + G_CALLBACK (full_header_structure_changed), etfci); + etfci->full_header_dimension_change_id = g_signal_connect ( + header, "dimension_change", + G_CALLBACK (full_header_dimension_changed), etfci); + e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci)); +} + +static void +etfci_drop_table_header (ETableFieldChooserItem *etfci) +{ + GObject *header; + + if (!etfci->header) + return; + + header = G_OBJECT (etfci->header); + if (etfci->table_header_structure_change_id) + g_signal_handler_disconnect ( + header, etfci->table_header_structure_change_id); + if (etfci->table_header_dimension_change_id) + g_signal_handler_disconnect ( + header, etfci->table_header_dimension_change_id); + etfci->table_header_structure_change_id = 0; + etfci->table_header_dimension_change_id = 0; + + if (header) + g_object_unref (header); + etfci->header = NULL; + etfci->height = 0; + e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci)); +} + +static void +table_header_structure_changed (ETableHeader *header, + ETableFieldChooserItem *etfci) +{ + e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci)); +} + +static void +table_header_dimension_changed (ETableHeader *header, + gint col, + ETableFieldChooserItem *etfci) +{ + e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci)); +} + +static void +etfci_add_table_header (ETableFieldChooserItem *etfci, + ETableHeader *header) +{ + etfci->header = header; + g_object_ref (etfci->header); + + etfci->table_header_structure_change_id = g_signal_connect ( + header, "structure_change", + G_CALLBACK (table_header_structure_changed), etfci); + etfci->table_header_dimension_change_id = g_signal_connect ( + header, "dimension_change", + G_CALLBACK (table_header_dimension_changed), etfci); + e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci)); +} + +static void +etfci_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GnomeCanvasItem *item; + ETableFieldChooserItem *etfci; + + item = GNOME_CANVAS_ITEM (object); + etfci = E_TABLE_FIELD_CHOOSER_ITEM (object); + + switch (property_id) { + case PROP_FULL_HEADER: + etfci_drop_full_header (etfci); + if (g_value_get_object (value)) + etfci_add_full_header ( + etfci, E_TABLE_HEADER ( + g_value_get_object (value))); + break; + + case PROP_HEADER: + etfci_drop_table_header (etfci); + if (g_value_get_object (value)) + etfci_add_table_header ( + etfci, E_TABLE_HEADER ( + g_value_get_object (value))); + break; + + case PROP_DND_CODE: + g_free (etfci->dnd_code); + etfci->dnd_code = g_strdup (g_value_get_string (value)); + break; + + case PROP_WIDTH: + etfci->width = g_value_get_double (value); + gnome_canvas_item_request_update (item); + break; + } +} + +static void +etfci_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + ETableFieldChooserItem *etfci; + + etfci = E_TABLE_FIELD_CHOOSER_ITEM (object); + + switch (property_id) { + + case PROP_DND_CODE: + g_value_set_string (value, etfci->dnd_code); + break; + case PROP_WIDTH: + g_value_set_double (value, etfci->width); + break; + case PROP_HEIGHT: + g_value_set_double (value, etfci->height); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +etfci_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + ETableFieldChooserItem *etfci) +{ + if (etfci->drag_col != -1) { + gchar *string = g_strdup_printf ("%d", etfci->drag_col); + gtk_selection_data_set ( + selection_data, + GDK_SELECTION_TYPE_STRING, + sizeof (string[0]), + (guchar *) string, + strlen (string)); + g_free (string); + } +} + +static void +etfci_drag_end (GtkWidget *canvas, + GdkDragContext *context, + ETableFieldChooserItem *etfci) +{ + etfci->drag_col = -1; +} + +static void +etfci_realize (GnomeCanvasItem *item) +{ + ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item); + + if (GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)-> realize) + (*GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->realize)(item); + + if (!etfci->font_desc) + etfci_font_load (etfci); + + etfci->drag_end_id = g_signal_connect ( + item->canvas, "drag_end", + G_CALLBACK (etfci_drag_end), etfci); + etfci->drag_data_get_id = g_signal_connect ( + item->canvas, "drag_data_get", + G_CALLBACK (etfci_drag_data_get), etfci); + e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etfci)); +} + +static void +etfci_unrealize (GnomeCanvasItem *item) +{ + ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item); + + if (etfci->font_desc) + pango_font_description_free (etfci->font_desc); + etfci->font_desc = NULL; + + g_signal_handler_disconnect (item->canvas, etfci->drag_end_id); + etfci->drag_end_id = 0; + g_signal_handler_disconnect (item->canvas, etfci->drag_data_get_id); + etfci->drag_data_get_id = 0; + + if (GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->unrealize) + (*GNOME_CANVAS_ITEM_CLASS (etfci_parent_class)->unrealize)(item); +} + +static void +etfci_draw (GnomeCanvasItem *item, + cairo_t *cr, + gint x, + gint y, + gint width, + gint height) +{ + ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item); + GnomeCanvas *canvas = item->canvas; + gint rows; + gint y1, y2; + gint row; + + if (etfci->combined_header == NULL) + return; + + rows = e_table_header_count (etfci->combined_header); + + y1 = y2 = 0; + for (row = 0; row < rows; row++, y1 = y2) { + ETableCol *ecol; + + ecol = e_table_header_get_column (etfci->combined_header, row); + + if (ecol->disabled) + continue; + + y2 += e_table_header_compute_height (ecol, GTK_WIDGET (canvas)); + + if (y1 > (y + height)) + break; + + if (y2 < y) + continue; + + cairo_save (cr); + + e_table_header_draw_button ( + cr, ecol, + GTK_WIDGET (canvas), + -x, y1 - y, + width, height, + etfci->width, y2 - y1, + E_TABLE_COL_ARROW_NONE); + + cairo_restore (cr); + } +} + +static GnomeCanvasItem * +etfci_point (GnomeCanvasItem *item, + gdouble x, + gdouble y, + gint cx, + gint cy) +{ + return item; +} + +static gboolean +etfci_maybe_start_drag (ETableFieldChooserItem *etfci, + gint x, + gint y) +{ + if (!etfci->maybe_drag) + return FALSE; + + if (MAX (abs (etfci->click_x - x), + abs (etfci->click_y - y)) <= 3) + return FALSE; + + return TRUE; +} + +static void +etfci_start_drag (ETableFieldChooserItem *etfci, + GdkEvent *event, + gdouble x, + gdouble y) +{ + GtkWidget *widget = GTK_WIDGET (GNOME_CANVAS_ITEM (etfci)->canvas); + GtkTargetList *list; + GdkDragContext *context; + ETableCol *ecol; + cairo_surface_t *cs; + cairo_t *cr; + gint drag_col; + gint button_height; + + GtkTargetEntry etfci_drag_types[] = { + { (gchar *) TARGET_ETABLE_COL_TYPE, 0, TARGET_ETABLE_COL_HEADER }, + }; + + if (etfci->combined_header == NULL) + return; + + drag_col = etfci_find_button (etfci, y); + + if (drag_col < 0 || drag_col > e_table_header_count (etfci->combined_header)) + return; + + ecol = e_table_header_get_column (etfci->combined_header, drag_col); + + if (ecol->disabled) + return; + + etfci->drag_col = ecol->col_idx; + + etfci_drag_types[0].target = g_strdup_printf ( + "%s-%s", etfci_drag_types[0].target, etfci->dnd_code); + d (g_print ("etfci - %s\n", etfci_drag_types[0].target)); + list = gtk_target_list_new (etfci_drag_types, G_N_ELEMENTS (etfci_drag_types)); + context = gtk_drag_begin (widget, list, GDK_ACTION_MOVE, 1, event); + g_free ((gpointer) etfci_drag_types[0].target); + + button_height = e_table_header_compute_height (ecol, widget); + cs = cairo_image_surface_create ( + CAIRO_FORMAT_ARGB32, + etfci->width, button_height); + cr = cairo_create (cs); + + e_table_header_draw_button ( + cr, ecol, + widget, 0, 0, + etfci->width, button_height, + etfci->width, button_height, + E_TABLE_COL_ARROW_NONE); + + gtk_drag_set_icon_surface (context, cs); + + cairo_surface_destroy (cs); + cairo_destroy (cr); + etfci->maybe_drag = FALSE; +} + +/* + * Handles the events on the ETableFieldChooserItem + */ +static gint +etfci_event (GnomeCanvasItem *item, + GdkEvent *e) +{ + ETableFieldChooserItem *etfci = E_TABLE_FIELD_CHOOSER_ITEM (item); + GnomeCanvas *canvas = item->canvas; + gint x, y; + + switch (e->type) { + case GDK_MOTION_NOTIFY: + gnome_canvas_w2c (canvas, e->motion.x, e->motion.y, &x, &y); + + if (etfci_maybe_start_drag (etfci, x, y)) + etfci_start_drag (etfci, e, x, y); + break; + + case GDK_BUTTON_PRESS: + gnome_canvas_w2c (canvas, e->button.x, e->button.y, &x, &y); + + if (e->button.button == 1) { + etfci->click_x = x; + etfci->click_y = y; + etfci->maybe_drag = TRUE; + } + break; + + case GDK_BUTTON_RELEASE: { + etfci->maybe_drag = FALSE; + break; + } + + default: + return FALSE; + } + return TRUE; +} + +static void +etfci_class_init (ETableFieldChooserItemClass *class) +{ + GnomeCanvasItemClass *item_class = GNOME_CANVAS_ITEM_CLASS (class); + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = etfci_dispose; + object_class->set_property = etfci_set_property; + object_class->get_property = etfci_get_property; + + item_class->update = etfci_update; + item_class->realize = etfci_realize; + item_class->unrealize = etfci_unrealize; + item_class->draw = etfci_draw; + item_class->point = etfci_point; + item_class->event = etfci_event; + + g_object_class_install_property ( + object_class, + PROP_DND_CODE, + g_param_spec_string ( + "dnd_code", + "DnD code", + NULL, + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_FULL_HEADER, + g_param_spec_object ( + "full_header", + "Full Header", + NULL, + E_TYPE_TABLE_HEADER, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_HEADER, + g_param_spec_object ( + "header", + "Header", + NULL, + E_TYPE_TABLE_HEADER, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_WIDTH, + g_param_spec_double ( + "width", + "Width", + NULL, + 0, G_MAXDOUBLE, 0, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_HEIGHT, + g_param_spec_double ( + "height", + "Height", + NULL, + 0, G_MAXDOUBLE, 0, + G_PARAM_READABLE)); +} + +static void +etfci_init (ETableFieldChooserItem *etfci) +{ + etfci->full_header = NULL; + etfci->header = NULL; + etfci->combined_header = NULL; + + etfci->height = etfci->width = 0; + + etfci->font_desc = NULL; + + etfci->full_header_structure_change_id = 0; + etfci->full_header_dimension_change_id = 0; + etfci->table_header_structure_change_id = 0; + etfci->table_header_dimension_change_id = 0; + + etfci->dnd_code = NULL; + + etfci->maybe_drag = 0; + etfci->drag_end_id = 0; + + e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM (etfci), etfci_reflow); +} + |