From d09d8de870b6697c8a8b262e7e077b871a69b315 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Mon, 10 Dec 2012 08:09:59 -0500 Subject: Consolidate base utility libraries into libeutil. Evolution consists of entirely too many small utility libraries, which increases linking and loading time, places a burden on higher layers of the application (e.g. modules) which has to remember to link to all the small in-tree utility libraries, and makes it difficult to generate API documentation for these utility libraries in one Gtk-Doc module. Merge the following utility libraries under the umbrella of libeutil, and enforce a single-include policy on libeutil so we can reorganize the files as desired without disrupting its pseudo-public API. libemail-utils/libemail-utils.la libevolution-utils/libevolution-utils.la filter/libfilter.la widgets/e-timezone-dialog/libetimezonedialog.la widgets/menus/libmenus.la widgets/misc/libemiscwidgets.la widgets/table/libetable.la widgets/text/libetext.la This also merges libedataserverui from the Evolution-Data-Server module, since Evolution is its only consumer nowadays, and I'd like to make some improvements to those APIs without concern for backward-compatibility. And finally, start a Gtk-Doc module for libeutil. It's going to be a project just getting all the symbols _listed_ much less _documented_. But the skeletal structure is in place and I'm off to a good start. --- e-util/e-cell-tree.c | 880 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 880 insertions(+) create mode 100644 e-util/e-cell-tree.c (limited to 'e-util/e-cell-tree.c') diff --git a/e-util/e-cell-tree.c b/e-util/e-cell-tree.c new file mode 100644 index 0000000000..085fb0cabe --- /dev/null +++ b/e-util/e-cell-tree.c @@ -0,0 +1,880 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * e-cell-tree.c - Tree cell object. + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + * Authors: + * Chris Toshok + * + * A majority of code taken from: + * + * the ECellText renderer. + * Copyright 1998, The Free Software Foundation + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include + +#include "gal-a11y-e-cell-registry.h" +#include "gal-a11y-e-cell-tree.h" + +#include "e-cell-tree.h" +#include "e-table-item.h" +#include "e-tree.h" +#include "e-tree-model.h" +#include "e-tree-table-adapter.h" + +G_DEFINE_TYPE (ECellTree, e_cell_tree, E_TYPE_CELL) + +typedef struct { + ECellView cell_view; + ECellView *subcell_view; + + GnomeCanvas *canvas; + gboolean prelit; + gint animate_timeout; + +} ECellTreeView; + +#define INDENT_AMOUNT 16 + +ECellView * +e_cell_tree_view_get_subcell_view (ECellView *ect) +{ + return ((ECellTreeView *) ect)->subcell_view; +} + +static ETreePath +e_cell_tree_get_node (ETableModel *table_model, + gint row) +{ + return e_table_model_value_at (table_model, -1, row); +} + +static ETreeModel * +e_cell_tree_get_tree_model (ETableModel *table_model, + gint row) +{ + return e_table_model_value_at (table_model, -2, row); +} + +static ETreeTableAdapter * +e_cell_tree_get_tree_table_adapter (ETableModel *table_model, + gint row) +{ + return e_table_model_value_at (table_model, -3, row); +} + +static gint +visible_depth_of_node (ETableModel *model, + gint row) +{ + ETreeModel *tree_model = e_cell_tree_get_tree_model (model, row); + ETreeTableAdapter *adapter = e_cell_tree_get_tree_table_adapter (model, row); + ETreePath path = e_cell_tree_get_node (model, row); + return (e_tree_model_node_depth (tree_model, path) + - (e_tree_table_adapter_root_node_is_visible (adapter) ? 0 : 1)); +} + +/* If this is changed to not include the width of the expansion pixmap + * if the path is not expandable, then max_width needs to change as + * well. */ +static gint +offset_of_node (ETableModel *table_model, + gint row) +{ + ETreeModel *tree_model = e_cell_tree_get_tree_model (table_model, row); + ETreePath path = e_cell_tree_get_node (table_model, row); + + if (visible_depth_of_node (table_model, row) >= 0 || + e_tree_model_node_is_expandable (tree_model, path)) { + return (visible_depth_of_node (table_model, row) + 1) * INDENT_AMOUNT; + } else { + return 0; + } +} + +/* + * ECell::new_view method + */ +static ECellView * +ect_new_view (ECell *ecell, + ETableModel *table_model, + gpointer e_table_item_view) +{ + ECellTree *ect = E_CELL_TREE (ecell); + ECellTreeView *tree_view = g_new0 (ECellTreeView, 1); + GnomeCanvas *canvas = GNOME_CANVAS_ITEM (e_table_item_view)->canvas; + + tree_view->cell_view.ecell = ecell; + tree_view->cell_view.e_table_model = table_model; + tree_view->cell_view.e_table_item_view = e_table_item_view; + tree_view->cell_view.kill_view_cb = NULL; + tree_view->cell_view.kill_view_cb_data = NULL; + + /* create our subcell view */ + tree_view->subcell_view = e_cell_new_view (ect->subcell, table_model, e_table_item_view /* XXX */); + + tree_view->canvas = canvas; + + return (ECellView *) tree_view; +} + +/* + * ECell::kill_view method + */ +static void +ect_kill_view (ECellView *ecv) +{ + ECellTreeView *tree_view = (ECellTreeView *) ecv; + + if (tree_view->cell_view.kill_view_cb) + (tree_view->cell_view.kill_view_cb)(ecv, tree_view->cell_view.kill_view_cb_data); + + if (tree_view->cell_view.kill_view_cb_data) + g_list_free (tree_view->cell_view.kill_view_cb_data); + + /* kill our subcell view */ + e_cell_kill_view (tree_view->subcell_view); + + g_free (tree_view); +} + +/* + * ECell::realize method + */ +static void +ect_realize (ECellView *ecell_view) +{ + ECellTreeView *tree_view = (ECellTreeView *) ecell_view; + + /* realize our subcell view */ + e_cell_realize (tree_view->subcell_view); + + if (E_CELL_CLASS (e_cell_tree_parent_class)->realize) + (* E_CELL_CLASS (e_cell_tree_parent_class)->realize) (ecell_view); +} + +/* + * ECell::unrealize method + */ +static void +ect_unrealize (ECellView *ecv) +{ + ECellTreeView *tree_view = (ECellTreeView *) ecv; + + /* unrealize our subcell view. */ + e_cell_unrealize (tree_view->subcell_view); + + if (E_CELL_CLASS (e_cell_tree_parent_class)->unrealize) + (* E_CELL_CLASS (e_cell_tree_parent_class)->unrealize) (ecv); +} + +static void +draw_expander (ECellTreeView *ectv, + cairo_t *cr, + GtkExpanderStyle expander_style, + GtkStateType state, + GdkRectangle *rect) +{ + GtkStyleContext *style_context; + GtkWidget *tree; + GtkStateFlags flags = 0; + gint exp_size; + + tree = gtk_widget_get_parent (GTK_WIDGET (ectv->canvas)); + style_context = gtk_widget_get_style_context (tree); + + gtk_style_context_save (style_context); + + gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_EXPANDER); + + switch (state) { + case GTK_STATE_PRELIGHT: + flags |= GTK_STATE_FLAG_PRELIGHT; + break; + case GTK_STATE_SELECTED: + flags |= GTK_STATE_FLAG_SELECTED; + break; + case GTK_STATE_INSENSITIVE: + flags |= GTK_STATE_FLAG_INSENSITIVE; + break; + default: + break; + } + + if (expander_style == GTK_EXPANDER_EXPANDED) + flags |= GTK_STATE_FLAG_ACTIVE; + + gtk_style_context_set_state (style_context, flags); + + gtk_widget_style_get (tree, "expander_size", &exp_size, NULL); + + cairo_save (cr); + + gtk_render_expander ( + style_context, cr, + (gdouble) rect->x + rect->width - exp_size, + (gdouble) (rect->y + rect->height / 2) - (exp_size / 2), + (gdouble) exp_size, + (gdouble) exp_size); + + cairo_restore (cr); + + gtk_style_context_restore (style_context); +} + +/* + * ECell::draw method + */ +static void +ect_draw (ECellView *ecell_view, + cairo_t *cr, + gint model_col, + gint view_col, + gint row, + ECellFlags flags, + gint x1, + gint y1, + gint x2, + gint y2) +{ + ECellTreeView *tree_view = (ECellTreeView *) ecell_view; + ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row); + ETreeTableAdapter *tree_table_adapter = e_cell_tree_get_tree_table_adapter (ecell_view->e_table_model, row); + ETreePath node; + GdkRectangle rect; + gint offset, subcell_offset; + + cairo_save (cr); + + /* only draw the tree effects if we're the active sort */ + if (/* XXX */ TRUE) { + GdkPixbuf *node_image; + gint node_image_width = 0, node_image_height = 0; + + tree_view->prelit = FALSE; + + node = e_cell_tree_get_node (ecell_view->e_table_model, row); + + offset = offset_of_node (ecell_view->e_table_model, row); + subcell_offset = offset; + + node_image = e_tree_model_icon_at (tree_model, node); + + if (node_image) { + node_image_width = gdk_pixbuf_get_width (node_image); + node_image_height = gdk_pixbuf_get_height (node_image); + } + + /* + * Be a nice citizen: clip to the region we are supposed to draw on + */ + rect.x = x1; + rect.y = y1; + rect.width = subcell_offset + node_image_width; + rect.height = y2 - y1; + + /* now draw our icon if we're expandable */ + if (e_tree_model_node_is_expandable (tree_model, node)) { + gboolean expanded = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node); + GdkRectangle r; + + r = rect; + r.width -= node_image_width + 2; + draw_expander (tree_view, cr, expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED, GTK_STATE_NORMAL, &r); + } + + if (node_image) { + gdk_cairo_set_source_pixbuf ( + cr, node_image, + x1 + subcell_offset, + y1 + (y2 - y1) / 2 - node_image_height / 2); + cairo_paint (cr); + + subcell_offset += node_image_width; + } + } + + /* Now cause our subcell to draw its contents, shifted by + * subcell_offset pixels */ + e_cell_draw ( + tree_view->subcell_view, cr, + model_col, view_col, row, flags, + x1 + subcell_offset, y1, x2, y2); + + cairo_restore (cr); +} + +static void +adjust_event_position (GdkEvent *event, + gint offset) +{ + switch (event->type) { + case GDK_BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + event->button.x += offset; + break; + case GDK_MOTION_NOTIFY: + event->motion.x += offset; + break; + default: + break; + } +} + +static gboolean +event_in_expander (GdkEvent *event, + gint offset, + gint height) +{ + switch (event->type) { + case GDK_BUTTON_PRESS: + return (event->button.x > (offset - INDENT_AMOUNT) && event->button.x < offset); + case GDK_MOTION_NOTIFY: + return (event->motion.x > (offset - INDENT_AMOUNT) && event->motion.x < offset && + event->motion.y > 2 && event->motion.y < (height - 2)); + default: + break; + } + + return FALSE; +} + +/* + * ECell::height method + */ +static gint +ect_height (ECellView *ecell_view, + gint model_col, + gint view_col, + gint row) +{ + ECellTreeView *tree_view = (ECellTreeView *) ecell_view; + + return (((e_cell_height (tree_view->subcell_view, model_col, view_col, row)) + 1) / 2) * 2; +} + +typedef struct { + ECellTreeView *ectv; + ETreeTableAdapter *etta; + ETreePath node; + gboolean expanded; + gboolean finish; + GdkRectangle area; +} animate_closure_t; + +static gboolean +animate_expander (gpointer data) +{ + GtkLayout *layout; + GdkWindow *window; + animate_closure_t *closure = (animate_closure_t *) data; + cairo_t *cr; + + if (closure->finish) { + e_tree_table_adapter_node_set_expanded (closure->etta, closure->node, !closure->expanded); + closure->ectv->animate_timeout = 0; + g_free (data); + return FALSE; + } + + layout = GTK_LAYOUT (closure->ectv->canvas); + window = gtk_layout_get_bin_window (layout); + + cr = gdk_cairo_create (window); + + draw_expander ( + closure->ectv, cr, closure->expanded ? + GTK_EXPANDER_SEMI_COLLAPSED : + GTK_EXPANDER_SEMI_EXPANDED, + GTK_STATE_NORMAL, &closure->area); + closure->finish = TRUE; + + cairo_destroy (cr); + + return TRUE; +} + +/* + * ECell::event method + */ +static gint +ect_event (ECellView *ecell_view, + GdkEvent *event, + gint model_col, + gint view_col, + gint row, + ECellFlags flags, + ECellActions *actions) +{ + GtkLayout *layout; + GdkWindow *window; + ECellTreeView *tree_view = (ECellTreeView *) ecell_view; + ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row); + ETreeTableAdapter *etta = e_cell_tree_get_tree_table_adapter (ecell_view->e_table_model, row); + ETreePath node = e_cell_tree_get_node (ecell_view->e_table_model, row); + gint offset = offset_of_node (ecell_view->e_table_model, row); + gint result; + + layout = GTK_LAYOUT (tree_view->canvas); + window = gtk_layout_get_bin_window (layout); + + switch (event->type) { + case GDK_BUTTON_PRESS: + + if (event_in_expander (event, offset, 0)) { + if (e_tree_model_node_is_expandable (tree_model, node)) { + gboolean expanded = e_tree_table_adapter_node_is_expanded (etta, node); + gint tmp_row = row; + GdkRectangle area; + animate_closure_t *closure = g_new0 (animate_closure_t, 1); + cairo_t *cr; + gint hgt; + + e_table_item_get_cell_geometry ( + tree_view->cell_view.e_table_item_view, + &tmp_row, &view_col, &area.x, &area.y, NULL, &area.height); + area.width = offset - 2; + hgt = e_cell_height (ecell_view, model_col, view_col, row); + + if (hgt != area.height) /* Composite cells */ + area.height += hgt; + + cr = gdk_cairo_create (window); + draw_expander ( + tree_view, cr, expanded ? + GTK_EXPANDER_SEMI_EXPANDED : + GTK_EXPANDER_SEMI_COLLAPSED, + GTK_STATE_NORMAL, &area); + cairo_destroy (cr); + + closure->ectv = tree_view; + closure->etta = etta; + closure->node = node; + closure->expanded = expanded; + closure->area = area; + tree_view->animate_timeout = g_timeout_add (50, animate_expander, closure); + return TRUE; + } + } + else if (event->button.x < (offset - INDENT_AMOUNT)) + return FALSE; + break; + + case GDK_MOTION_NOTIFY: + + if (e_tree_model_node_is_expandable (tree_model, node)) { + gint height = ect_height (ecell_view, model_col, view_col, row); + GdkRectangle area; + gboolean in_expander = event_in_expander (event, offset, height); + + if (tree_view->prelit ^ in_expander) { + gint tmp_row = row; + cairo_t *cr; + + e_table_item_get_cell_geometry ( + tree_view->cell_view.e_table_item_view, + &tmp_row, &view_col, &area.x, &area.y, NULL, &area.height); + area.width = offset - 2; + + cr = gdk_cairo_create (window); + draw_expander ( + tree_view, cr, + e_tree_table_adapter_node_is_expanded (etta, node) ? + GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED, + in_expander ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL, &area); + cairo_destroy (cr); + + tree_view->prelit = in_expander; + return TRUE; + } + + } + break; + + case GDK_LEAVE_NOTIFY: + + if (tree_view->prelit) { + gint tmp_row = row; + GdkRectangle area; + cairo_t *cr; + + e_table_item_get_cell_geometry ( + tree_view->cell_view.e_table_item_view, + &tmp_row, &view_col, &area.x, &area.y, NULL, &area.height); + area.width = offset - 2; + + cr = gdk_cairo_create (window); + draw_expander ( + tree_view, cr, + e_tree_table_adapter_node_is_expanded (etta, node) ? + GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED, + GTK_STATE_NORMAL, &area); + cairo_destroy (cr); + + tree_view->prelit = FALSE; + } + return TRUE; + + default: + break; + } + + adjust_event_position (event, -offset); + result = e_cell_event (tree_view->subcell_view, event, model_col, view_col, row, flags, actions); + adjust_event_position (event, offset); + + return result; +} + +/* + * ECell::max_width method + */ +static gint +ect_max_width (ECellView *ecell_view, + gint model_col, + gint view_col) +{ + ECellTreeView *tree_view = (ECellTreeView *) ecell_view; + gint row; + gint number_of_rows; + gint max_width = 0; + gint width = 0; + gint subcell_max_width = 0; + gboolean per_row = e_cell_max_width_by_row_implemented (tree_view->subcell_view); + + number_of_rows = e_table_model_row_count (ecell_view->e_table_model); + + if (!per_row) + subcell_max_width = e_cell_max_width (tree_view->subcell_view, model_col, view_col); + + for (row = 0; row < number_of_rows; row++) { + ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row); + ETreePath node; + GdkPixbuf *node_image; + gint node_image_width = 0; + + gint offset, subcell_offset; +#if 0 + gboolean expanded, expandable; + ETreeTableAdapter *tree_table_adapter = e_cell_tree_get_tree_table_adapter (ecell_view->e_table_model, row); +#endif + + node = e_cell_tree_get_node (ecell_view->e_table_model, row); + + offset = offset_of_node (ecell_view->e_table_model, row); + subcell_offset = offset; + + node_image = e_tree_model_icon_at (tree_model, node); + + if (node_image) { + node_image_width = gdk_pixbuf_get_width (node_image); + } + + width = subcell_offset + node_image_width; + + if (per_row) + width += e_cell_max_width_by_row (tree_view->subcell_view, model_col, view_col, row); + else + width += subcell_max_width; + +#if 0 + expandable = e_tree_model_node_is_expandable (tree_model, node); + expanded = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node); + + /* This is unnecessary since this is already handled + * by the offset_of_node function. If that changes, + * this will have to change too. */ + + if (expandable) { + GdkPixbuf *image; + + image = (expanded + ? E_CELL_TREE (tree_view->cell_view.ecell)->open_pixbuf + : E_CELL_TREE (tree_view->cell_view.ecell)->closed_pixbuf); + + width += gdk_pixbuf_get_width (image); + } +#endif + + max_width = MAX (max_width, width); + } + + return max_width; +} + +/* + * ECellView::get_bg_color method + */ +static gchar * +ect_get_bg_color (ECellView *ecell_view, + gint row) +{ + ECellTreeView *tree_view = (ECellTreeView *) ecell_view; + + return e_cell_get_bg_color (tree_view->subcell_view, row); +} + +/* + * ECellView::enter_edit method + */ +static gpointer +ect_enter_edit (ECellView *ecell_view, + gint model_col, + gint view_col, + gint row) +{ + /* just defer to our subcell's view */ + ECellTreeView *tree_view = (ECellTreeView *) ecell_view; + + return e_cell_enter_edit (tree_view->subcell_view, model_col, view_col, row); +} + +/* + * ECellView::leave_edit method + */ +static void +ect_leave_edit (ECellView *ecell_view, + gint model_col, + gint view_col, + gint row, + gpointer edit_context) +{ + /* just defer to our subcell's view */ + ECellTreeView *tree_view = (ECellTreeView *) ecell_view; + + e_cell_leave_edit (tree_view->subcell_view, model_col, view_col, row, edit_context); +} + +static void +ect_print (ECellView *ecell_view, + GtkPrintContext *context, + gint model_col, + gint view_col, + gint row, + gdouble width, + gdouble height) +{ + ECellTreeView *tree_view = (ECellTreeView *) ecell_view; + cairo_t *cr = gtk_print_context_get_cairo_context (context); + + cairo_save (cr); + + if (/* XXX only if we're the active sort */ TRUE) { + ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row); + ETreeTableAdapter *tree_table_adapter = e_cell_tree_get_tree_table_adapter (ecell_view->e_table_model, row); + ETreePath node = e_cell_tree_get_node (ecell_view->e_table_model, row); + gint offset = offset_of_node (ecell_view->e_table_model, row); + gint subcell_offset = offset; + gboolean expandable = e_tree_model_node_is_expandable (tree_model, node); + + /* draw our lines */ + if (E_CELL_TREE (tree_view->cell_view.ecell)->draw_lines) { + gint depth; + + if (!e_tree_model_node_is_root (tree_model, node) + || e_tree_model_node_get_children (tree_model, node, NULL) > 0) { + cairo_move_to ( + cr, + offset - INDENT_AMOUNT / 2, + height / 2); + cairo_line_to (cr, offset, height / 2); + } + + if (visible_depth_of_node (ecell_view->e_table_model, row) != 0) { + cairo_move_to ( + cr, + offset - INDENT_AMOUNT / 2, height); + cairo_line_to ( + cr, + offset - INDENT_AMOUNT / 2, + e_tree_table_adapter_node_get_next + (tree_table_adapter, node) ? 0 : + height / 2); + } + + /* now traverse back up to the root of the tree, checking at + * each level if the node has siblings, and drawing the + * correct vertical pipe for it's configuration. */ + node = e_tree_model_node_get_parent (tree_model, node); + depth = visible_depth_of_node (ecell_view->e_table_model, row) - 1; + offset -= INDENT_AMOUNT; + while (node && depth != 0) { + if (e_tree_table_adapter_node_get_next (tree_table_adapter, node)) { + cairo_move_to ( + cr, + offset - INDENT_AMOUNT / 2, + height); + cairo_line_to ( + cr, + offset - INDENT_AMOUNT / 2, 0); + } + node = e_tree_model_node_get_parent (tree_model, node); + depth--; + offset -= INDENT_AMOUNT; + } + } + + /* now draw our icon if we're expandable */ + if (expandable) { + gboolean expanded; + GdkRectangle r; + gint exp_size = 0; + + gtk_widget_style_get (GTK_WIDGET (gtk_widget_get_parent (GTK_WIDGET (tree_view->canvas))), "expander_size", &exp_size, NULL); + + node = e_cell_tree_get_node (ecell_view->e_table_model, row); + expanded = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node); + + r.x = 0; + r.y = 0; + r.width = MIN (width, exp_size); + r.height = height; + + draw_expander (tree_view, cr, expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED, GTK_STATE_NORMAL, &r); + } + + cairo_stroke (cr); + + cairo_translate (cr, subcell_offset, 0); + width -= subcell_offset; + } + + cairo_restore (cr); + + e_cell_print (tree_view->subcell_view, context, model_col, view_col, row, width, height); +} + +static gdouble +ect_print_height (ECellView *ecell_view, + GtkPrintContext *context, + gint model_col, + gint view_col, + gint row, + gdouble width) +{ + return 12; /* XXX */ +} + +/* + * GObject::dispose method + */ +static void +ect_dispose (GObject *object) +{ + ECellTree *ect = E_CELL_TREE (object); + + /* destroy our subcell */ + if (ect->subcell) + g_object_unref (ect->subcell); + ect->subcell = NULL; + + G_OBJECT_CLASS (e_cell_tree_parent_class)->dispose (object); +} + +static void +e_cell_tree_class_init (ECellTreeClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + ECellClass *ecc = E_CELL_CLASS (class); + + object_class->dispose = ect_dispose; + + ecc->new_view = ect_new_view; + ecc->kill_view = ect_kill_view; + ecc->realize = ect_realize; + ecc->unrealize = ect_unrealize; + ecc->draw = ect_draw; + ecc->event = ect_event; + ecc->height = ect_height; + ecc->enter_edit = ect_enter_edit; + ecc->leave_edit = ect_leave_edit; + ecc->print = ect_print; + ecc->print_height = ect_print_height; + ecc->max_width = ect_max_width; + ecc->get_bg_color = ect_get_bg_color; + + gal_a11y_e_cell_registry_add_cell_type (NULL, E_TYPE_CELL_TREE, gal_a11y_e_cell_tree_new); +} + +static void +e_cell_tree_init (ECellTree *ect) +{ + /* nothing to do */ +} + +/** + * e_cell_tree_construct: + * @ect: the ECellTree we're constructing. + * @draw_lines: whether or not to draw the lines between parents/children/siblings. + * @subcell: the ECell to render to the right of the tree effects. + * + * Constructs an ECellTree. used by subclasses that need to + * initialize a nested ECellTree. See e_cell_tree_new() for more info. + * + **/ +void +e_cell_tree_construct (ECellTree *ect, + gboolean draw_lines, + ECell *subcell) +{ + ect->subcell = subcell; + if (subcell) + g_object_ref_sink (subcell); + + ect->draw_lines = draw_lines; +} + +/** + * e_cell_tree_new: + * @draw_lines: whether or not to draw the lines between parents/children/siblings. + * @subcell: the ECell to render to the right of the tree effects. + * + * Creates a new ECell renderer that can be used to render tree + * effects that come from an ETreeModel. Various assumptions are made + * as to the fact that the ETableModel the ETable this cell is + * associated with is in fact an ETreeModel. The cell uses special + * columns to get at structural information (needed to draw the + * lines/icons. + * + * Return value: an ECell object that can be used to render trees. + **/ +ECell * +e_cell_tree_new (gboolean draw_lines, + ECell *subcell) +{ + ECellTree *ect = g_object_new (E_TYPE_CELL_TREE, NULL); + + e_cell_tree_construct (ect, draw_lines, subcell); + + return (ECell *) ect; +} + -- cgit v1.2.3