aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-table-field-chooser-item.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-table-field-chooser-item.c')
-rw-r--r--e-util/e-table-field-chooser-item.c749
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);
+}
+