evolution-3.6.4/widgets/table/e-cell-tree.c

Location Tool Test ID Function Issue
e-cell-tree.c:298:0 cppcheck uninitvar Uninitialized variable: subcell_offset
e-cell-tree.c:298:0 cppcheck uninitvar Uninitialized variable: subcell_offset
  1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
  2 /*
  3  * e-cell-tree.c - Tree cell object.
  4  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  5  *
  6  * Authors:
  7  *   Chris Toshok <toshok@ximian.com>
  8  *
  9  * A majority of code taken from:
 10  *
 11  * the ECellText renderer.
 12  * Copyright 1998, The Free Software Foundation
 13  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 14  *
 15  * This library is free software; you can redistribute it and/or
 16  * modify it under the terms of the GNU Library General Public License as
 17  * published by the Free Software Foundation; either version 2 of the
 18  * License, or (at your option) any later version.
 19  *
 20  * This library is distributed in the hope that it will be useful, but
 21  * WITHOUT ANY WARRANTY; without even the implied warranty of
 22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 23  * Library General Public License for more details.
 24  *
 25  * You should have received a copy of the GNU Library General Public
 26  * License along with this library; if not, write to the Free Software
 27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 28  * 02110-1301, USA.
 29  */
 30 
 31 #ifdef HAVE_CONFIG_H
 32 #include <config.h>
 33 #endif
 34 
 35 #include <ctype.h>
 36 #include <math.h>
 37 #include <stdio.h>
 38 
 39 #include <gdk/gdkkeysyms.h>
 40 #include <gtk/gtk.h>
 41 #include <libgnomecanvas/libgnomecanvas.h>
 42 
 43 #include "gal-a11y-e-cell-registry.h"
 44 #include "gal-a11y-e-cell-tree.h"
 45 #include "e-util/e-util.h"
 46 
 47 #include "e-cell-tree.h"
 48 #include "e-table-item.h"
 49 #include "e-tree.h"
 50 #include "e-tree-model.h"
 51 #include "e-tree-table-adapter.h"
 52 
 53 G_DEFINE_TYPE (ECellTree, e_cell_tree, E_TYPE_CELL)
 54 
 55 typedef struct {
 56 	ECellView    cell_view;
 57 	ECellView   *subcell_view;
 58 
 59 	GnomeCanvas *canvas;
 60 	gboolean prelit;
 61 	gint animate_timeout;
 62 
 63 } ECellTreeView;
 64 
 65 #define INDENT_AMOUNT 16
 66 
 67 ECellView *
 68 e_cell_tree_view_get_subcell_view (ECellView *ect)
 69 {
 70 	return ((ECellTreeView *) ect)->subcell_view;
 71 }
 72 
 73 static ETreePath
 74 e_cell_tree_get_node (ETableModel *table_model,
 75                       gint row)
 76 {
 77 	return e_table_model_value_at (table_model, -1, row);
 78 }
 79 
 80 static ETreeModel *
 81 e_cell_tree_get_tree_model (ETableModel *table_model,
 82                             gint row)
 83 {
 84 	return e_table_model_value_at (table_model, -2, row);
 85 }
 86 
 87 static ETreeTableAdapter *
 88 e_cell_tree_get_tree_table_adapter (ETableModel *table_model,
 89                                     gint row)
 90 {
 91 	return e_table_model_value_at (table_model, -3, row);
 92 }
 93 
 94 static gint
 95 visible_depth_of_node (ETableModel *model,
 96                        gint row)
 97 {
 98 	ETreeModel *tree_model = e_cell_tree_get_tree_model (model, row);
 99 	ETreeTableAdapter *adapter = e_cell_tree_get_tree_table_adapter (model, row);
100 	ETreePath path = e_cell_tree_get_node (model, row);
101 	return (e_tree_model_node_depth (tree_model, path)
102 		- (e_tree_table_adapter_root_node_is_visible (adapter) ? 0 : 1));
103 }
104 
105 /* If this is changed to not include the width of the expansion pixmap
106  * if the path is not expandable, then max_width needs to change as
107  * well. */
108 static gint
109 offset_of_node (ETableModel *table_model,
110                 gint row)
111 {
112 	ETreeModel *tree_model = e_cell_tree_get_tree_model (table_model, row);
113 	ETreePath path = e_cell_tree_get_node (table_model, row);
114 
115 	if (visible_depth_of_node (table_model, row) >= 0 ||
116 	    e_tree_model_node_is_expandable (tree_model, path)) {
117 		return (visible_depth_of_node (table_model, row) + 1) * INDENT_AMOUNT;
118 	} else {
119 		return 0;
120 	}
121 }
122 
123 /*
124  * ECell::new_view method
125  */
126 static ECellView *
127 ect_new_view (ECell *ecell,
128               ETableModel *table_model,
129               gpointer e_table_item_view)
130 {
131 	ECellTree *ect = E_CELL_TREE (ecell);
132 	ECellTreeView *tree_view = g_new0 (ECellTreeView, 1);
133 	GnomeCanvas *canvas = GNOME_CANVAS_ITEM (e_table_item_view)->canvas;
134 
135 	tree_view->cell_view.ecell = ecell;
136 	tree_view->cell_view.e_table_model = table_model;
137 	tree_view->cell_view.e_table_item_view = e_table_item_view;
138 	tree_view->cell_view.kill_view_cb = NULL;
139 	tree_view->cell_view.kill_view_cb_data = NULL;
140 
141 	/* create our subcell view */
142 	tree_view->subcell_view = e_cell_new_view (ect->subcell, table_model, e_table_item_view /* XXX */);
143 
144 	tree_view->canvas = canvas;
145 
146 	return (ECellView *) tree_view;
147 }
148 
149 /*
150  * ECell::kill_view method
151  */
152 static void
153 ect_kill_view (ECellView *ecv)
154 {
155 	ECellTreeView *tree_view = (ECellTreeView *) ecv;
156 
157 	if (tree_view->cell_view.kill_view_cb)
158 	    (tree_view->cell_view.kill_view_cb)(ecv, tree_view->cell_view.kill_view_cb_data);
159 
160 	if (tree_view->cell_view.kill_view_cb_data)
161 	    g_list_free (tree_view->cell_view.kill_view_cb_data);
162 
163 	/* kill our subcell view */
164 	e_cell_kill_view (tree_view->subcell_view);
165 
166 	g_free (tree_view);
167 }
168 
169 /*
170  * ECell::realize method
171  */
172 static void
173 ect_realize (ECellView *ecell_view)
174 {
175 	ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
176 
177 	/* realize our subcell view */
178 	e_cell_realize (tree_view->subcell_view);
179 
180 	if (E_CELL_CLASS (e_cell_tree_parent_class)->realize)
181 		(* E_CELL_CLASS (e_cell_tree_parent_class)->realize) (ecell_view);
182 }
183 
184 /*
185  * ECell::unrealize method
186  */
187 static void
188 ect_unrealize (ECellView *ecv)
189 {
190 	ECellTreeView *tree_view = (ECellTreeView *) ecv;
191 
192 	/* unrealize our subcell view. */
193 	e_cell_unrealize (tree_view->subcell_view);
194 
195 	if (E_CELL_CLASS (e_cell_tree_parent_class)->unrealize)
196 		(* E_CELL_CLASS (e_cell_tree_parent_class)->unrealize) (ecv);
197 }
198 
199 static void
200 draw_expander (ECellTreeView *ectv,
201                cairo_t *cr,
202                GtkExpanderStyle expander_style,
203                GtkStateType state,
204                GdkRectangle *rect)
205 {
206 	GtkStyle *style;
207 	GtkWidget *tree;
208 	gint exp_size;
209 
210 	tree = gtk_widget_get_parent (GTK_WIDGET (ectv->canvas));
211 	style = gtk_widget_get_style (tree);
212 
213 	gtk_widget_style_get (tree, "expander_size", &exp_size, NULL);
214 
215 	gtk_paint_expander (
216 		style, cr, state, tree, "treeview",
217 		rect->x + rect->width - exp_size / 2,
218 		rect->y + rect->height / 2, expander_style);
219 }
220 
221 /*
222  * ECell::draw method
223  */
224 static void
225 ect_draw (ECellView *ecell_view,
226           cairo_t *cr,
227           gint model_col,
228           gint view_col,
229           gint row,
230           ECellFlags flags,
231           gint x1,
232           gint y1,
233           gint x2,
234           gint y2)
235 {
236 	ECellTreeView *tree_view = (ECellTreeView *) ecell_view;
237 	ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row);
238 	ETreeTableAdapter *tree_table_adapter = e_cell_tree_get_tree_table_adapter (ecell_view->e_table_model, row);
239 	ETreePath node;
240 	GdkRectangle rect;
241 	gint offset, subcell_offset;
242 
243 	cairo_save (cr);
244 
245 	/* only draw the tree effects if we're the active sort */
246 	if (/* XXX */ TRUE) {
247 		GdkPixbuf *node_image;
248 		gint node_image_width = 0, node_image_height = 0;
249 
250 		tree_view->prelit = FALSE;
251 
252 		node = e_cell_tree_get_node (ecell_view->e_table_model, row);
253 
254 		offset = offset_of_node (ecell_view->e_table_model, row);
255 		subcell_offset = offset;
256 
257 		node_image = e_tree_model_icon_at (tree_model, node);
258 
259 		if (node_image) {
260 			node_image_width = gdk_pixbuf_get_width (node_image);
261 			node_image_height = gdk_pixbuf_get_height (node_image);
262 		}
263 
264 		/*
265 		 * Be a nice citizen: clip to the region we are supposed to draw on
266 		 */
267 		rect.x = x1;
268 		rect.y = y1;
269 		rect.width = subcell_offset + node_image_width;
270 		rect.height = y2 - y1;
271 
272 		/* now draw our icon if we're expandable */
273 		if (e_tree_model_node_is_expandable (tree_model, node)) {
274 			gboolean expanded = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node);
275 			GdkRectangle r;
276 
277 			r = rect;
278 			r.width -= node_image_width + 2;
279 			draw_expander (tree_view, cr, expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED, GTK_STATE_NORMAL, &r);
280 		}
281 
282 		if (node_image) {
283 			gdk_cairo_set_source_pixbuf (
284 				cr, node_image,
285 				x1 + subcell_offset,
286 				y1 + (y2 - y1) / 2 - node_image_height / 2);
287 			cairo_paint (cr);
288 
289 			subcell_offset += node_image_width;
290 		}
291 	}
292 
293 	/* Now cause our subcell to draw its contents, shifted by
294 	 * subcell_offset pixels */
295 	e_cell_draw (
296 		tree_view->subcell_view, cr,
297 		model_col, view_col, row, flags,
298 		x1 + subcell_offset, y1, x2, y2);
Uninitialized variable: subcell_offset
(emitted by cppcheck)
Uninitialized variable: subcell_offset
(emitted by cppcheck)
299 300 cairo_restore (cr); 301 } 302 303 static void 304 adjust_event_position (GdkEvent *event, 305 gint offset) 306 { 307 switch (event->type) { 308 case GDK_BUTTON_PRESS: 309 case GDK_BUTTON_RELEASE: 310 case GDK_2BUTTON_PRESS: 311 case GDK_3BUTTON_PRESS: 312 event->button.x += offset; 313 break; 314 case GDK_MOTION_NOTIFY: 315 event->motion.x += offset; 316 break; 317 default: 318 break; 319 } 320 } 321 322 static gboolean 323 event_in_expander (GdkEvent *event, 324 gint offset, 325 gint height) 326 { 327 switch (event->type) { 328 case GDK_BUTTON_PRESS: 329 return (event->button.x > (offset - INDENT_AMOUNT) && event->button.x < offset); 330 case GDK_MOTION_NOTIFY: 331 return (event->motion.x > (offset - INDENT_AMOUNT) && event->motion.x < offset && 332 event->motion.y > 2 && event->motion.y < (height - 2)); 333 default: 334 break; 335 } 336 337 return FALSE; 338 } 339 340 /* 341 * ECell::height method 342 */ 343 static gint 344 ect_height (ECellView *ecell_view, 345 gint model_col, 346 gint view_col, 347 gint row) 348 { 349 ECellTreeView *tree_view = (ECellTreeView *) ecell_view; 350 351 return (((e_cell_height (tree_view->subcell_view, model_col, view_col, row)) + 1) / 2) * 2; 352 } 353 354 typedef struct { 355 ECellTreeView *ectv; 356 ETreeTableAdapter *etta; 357 ETreePath node; 358 gboolean expanded; 359 gboolean finish; 360 GdkRectangle area; 361 } animate_closure_t; 362 363 static gboolean 364 animate_expander (gpointer data) 365 { 366 GtkLayout *layout; 367 GdkWindow *window; 368 animate_closure_t *closure = (animate_closure_t *) data; 369 cairo_t *cr; 370 371 if (closure->finish) { 372 e_tree_table_adapter_node_set_expanded (closure->etta, closure->node, !closure->expanded); 373 closure->ectv->animate_timeout = 0; 374 g_free (data); 375 return FALSE; 376 } 377 378 layout = GTK_LAYOUT (closure->ectv->canvas); 379 window = gtk_layout_get_bin_window (layout); 380 381 cr = gdk_cairo_create (window); 382 383 draw_expander ( 384 closure->ectv, cr, closure->expanded ? 385 GTK_EXPANDER_SEMI_COLLAPSED : 386 GTK_EXPANDER_SEMI_EXPANDED, 387 GTK_STATE_NORMAL, &closure->area); 388 closure->finish = TRUE; 389 390 cairo_destroy (cr); 391 392 return TRUE; 393 } 394 395 /* 396 * ECell::event method 397 */ 398 static gint 399 ect_event (ECellView *ecell_view, 400 GdkEvent *event, 401 gint model_col, 402 gint view_col, 403 gint row, 404 ECellFlags flags, 405 ECellActions *actions) 406 { 407 GtkLayout *layout; 408 GdkWindow *window; 409 ECellTreeView *tree_view = (ECellTreeView *) ecell_view; 410 ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row); 411 ETreeTableAdapter *etta = e_cell_tree_get_tree_table_adapter (ecell_view->e_table_model, row); 412 ETreePath node = e_cell_tree_get_node (ecell_view->e_table_model, row); 413 gint offset = offset_of_node (ecell_view->e_table_model, row); 414 gint result; 415 416 layout = GTK_LAYOUT (tree_view->canvas); 417 window = gtk_layout_get_bin_window (layout); 418 419 switch (event->type) { 420 case GDK_BUTTON_PRESS: 421 422 if (event_in_expander (event, offset, 0)) { 423 if (e_tree_model_node_is_expandable (tree_model, node)) { 424 gboolean expanded = e_tree_table_adapter_node_is_expanded (etta, node); 425 gint tmp_row = row; 426 GdkRectangle area; 427 animate_closure_t *closure = g_new0 (animate_closure_t, 1); 428 cairo_t *cr; 429 gint hgt; 430 431 e_table_item_get_cell_geometry ( 432 tree_view->cell_view.e_table_item_view, 433 &tmp_row, &view_col, &area.x, &area.y, NULL, &area.height); 434 area.width = offset - 2; 435 hgt = e_cell_height (ecell_view, model_col, view_col, row); 436 437 if (hgt != area.height) /* Composite cells */ 438 area.height += hgt; 439 440 cr = gdk_cairo_create (window); 441 draw_expander ( 442 tree_view, cr, expanded ? 443 GTK_EXPANDER_SEMI_EXPANDED : 444 GTK_EXPANDER_SEMI_COLLAPSED, 445 GTK_STATE_NORMAL, &area); 446 cairo_destroy (cr); 447 448 closure->ectv = tree_view; 449 closure->etta = etta; 450 closure->node = node; 451 closure->expanded = expanded; 452 closure->area = area; 453 tree_view->animate_timeout = g_timeout_add (50, animate_expander, closure); 454 return TRUE; 455 } 456 } 457 else if (event->button.x < (offset - INDENT_AMOUNT)) 458 return FALSE; 459 break; 460 461 case GDK_MOTION_NOTIFY: 462 463 if (e_tree_model_node_is_expandable (tree_model, node)) { 464 gint height = ect_height (ecell_view, model_col, view_col, row); 465 GdkRectangle area; 466 gboolean in_expander = event_in_expander (event, offset, height); 467 468 if (tree_view->prelit ^ in_expander) { 469 gint tmp_row = row; 470 cairo_t *cr; 471 472 e_table_item_get_cell_geometry ( 473 tree_view->cell_view.e_table_item_view, 474 &tmp_row, &view_col, &area.x, &area.y, NULL, &area.height); 475 area.width = offset - 2; 476 477 cr = gdk_cairo_create (window); 478 draw_expander ( 479 tree_view, cr, 480 e_tree_table_adapter_node_is_expanded (etta, node) ? 481 GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED, 482 in_expander ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL, &area); 483 cairo_destroy (cr); 484 485 tree_view->prelit = in_expander; 486 return TRUE; 487 } 488 489 } 490 break; 491 492 case GDK_LEAVE_NOTIFY: 493 494 if (tree_view->prelit) { 495 gint tmp_row = row; 496 GdkRectangle area; 497 cairo_t *cr; 498 499 e_table_item_get_cell_geometry ( 500 tree_view->cell_view.e_table_item_view, 501 &tmp_row, &view_col, &area.x, &area.y, NULL, &area.height); 502 area.width = offset - 2; 503 504 cr = gdk_cairo_create (window); 505 draw_expander ( 506 tree_view, cr, 507 e_tree_table_adapter_node_is_expanded (etta, node) ? 508 GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED, 509 GTK_STATE_NORMAL, &area); 510 cairo_destroy (cr); 511 512 tree_view->prelit = FALSE; 513 } 514 return TRUE; 515 516 default: 517 break; 518 } 519 520 adjust_event_position (event, -offset); 521 result = e_cell_event (tree_view->subcell_view, event, model_col, view_col, row, flags, actions); 522 adjust_event_position (event, offset); 523 524 return result; 525 } 526 527 /* 528 * ECell::max_width method 529 */ 530 static gint 531 ect_max_width (ECellView *ecell_view, 532 gint model_col, 533 gint view_col) 534 { 535 ECellTreeView *tree_view = (ECellTreeView *) ecell_view; 536 gint row; 537 gint number_of_rows; 538 gint max_width = 0; 539 gint width = 0; 540 gint subcell_max_width = 0; 541 gboolean per_row = e_cell_max_width_by_row_implemented (tree_view->subcell_view); 542 543 number_of_rows = e_table_model_row_count (ecell_view->e_table_model); 544 545 if (!per_row) 546 subcell_max_width = e_cell_max_width (tree_view->subcell_view, model_col, view_col); 547 548 for (row = 0; row < number_of_rows; row++) { 549 ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row); 550 ETreePath node; 551 GdkPixbuf *node_image; 552 gint node_image_width = 0; 553 554 gint offset, subcell_offset; 555 #if 0 556 gboolean expanded, expandable; 557 ETreeTableAdapter *tree_table_adapter = e_cell_tree_get_tree_table_adapter (ecell_view->e_table_model, row); 558 #endif 559 560 node = e_cell_tree_get_node (ecell_view->e_table_model, row); 561 562 offset = offset_of_node (ecell_view->e_table_model, row); 563 subcell_offset = offset; 564 565 node_image = e_tree_model_icon_at (tree_model, node); 566 567 if (node_image) { 568 node_image_width = gdk_pixbuf_get_width (node_image); 569 } 570 571 width = subcell_offset + node_image_width; 572 573 if (per_row) 574 width += e_cell_max_width_by_row (tree_view->subcell_view, model_col, view_col, row); 575 else 576 width += subcell_max_width; 577 578 #if 0 579 expandable = e_tree_model_node_is_expandable (tree_model, node); 580 expanded = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node); 581 582 /* This is unnecessary since this is already handled 583 * by the offset_of_node function. If that changes, 584 * this will have to change too. */ 585 586 if (expandable) { 587 GdkPixbuf *image; 588 589 image = (expanded 590 ? E_CELL_TREE (tree_view->cell_view.ecell)->open_pixbuf 591 : E_CELL_TREE (tree_view->cell_view.ecell)->closed_pixbuf); 592 593 width += gdk_pixbuf_get_width (image); 594 } 595 #endif 596 597 max_width = MAX (max_width, width); 598 } 599 600 return max_width; 601 } 602 603 /* 604 * ECellView::get_bg_color method 605 */ 606 static gchar * 607 ect_get_bg_color (ECellView *ecell_view, 608 gint row) 609 { 610 ECellTreeView *tree_view = (ECellTreeView *) ecell_view; 611 612 return e_cell_get_bg_color (tree_view->subcell_view, row); 613 } 614 615 /* 616 * ECellView::enter_edit method 617 */ 618 static gpointer 619 ect_enter_edit (ECellView *ecell_view, 620 gint model_col, 621 gint view_col, 622 gint row) 623 { 624 /* just defer to our subcell's view */ 625 ECellTreeView *tree_view = (ECellTreeView *) ecell_view; 626 627 return e_cell_enter_edit (tree_view->subcell_view, model_col, view_col, row); 628 } 629 630 /* 631 * ECellView::leave_edit method 632 */ 633 static void 634 ect_leave_edit (ECellView *ecell_view, 635 gint model_col, 636 gint view_col, 637 gint row, 638 gpointer edit_context) 639 { 640 /* just defer to our subcell's view */ 641 ECellTreeView *tree_view = (ECellTreeView *) ecell_view; 642 643 e_cell_leave_edit (tree_view->subcell_view, model_col, view_col, row, edit_context); 644 } 645 646 static void 647 ect_print (ECellView *ecell_view, 648 GtkPrintContext *context, 649 gint model_col, 650 gint view_col, 651 gint row, 652 gdouble width, 653 gdouble height) 654 { 655 ECellTreeView *tree_view = (ECellTreeView *) ecell_view; 656 cairo_t *cr = gtk_print_context_get_cairo_context (context); 657 658 cairo_save (cr); 659 660 if (/* XXX only if we're the active sort */ TRUE) { 661 ETreeModel *tree_model = e_cell_tree_get_tree_model (ecell_view->e_table_model, row); 662 ETreeTableAdapter *tree_table_adapter = e_cell_tree_get_tree_table_adapter (ecell_view->e_table_model, row); 663 ETreePath node = e_cell_tree_get_node (ecell_view->e_table_model, row); 664 gint offset = offset_of_node (ecell_view->e_table_model, row); 665 gint subcell_offset = offset; 666 gboolean expandable = e_tree_model_node_is_expandable (tree_model, node); 667 668 /* draw our lines */ 669 if (E_CELL_TREE (tree_view->cell_view.ecell)->draw_lines) { 670 gint depth; 671 672 if (!e_tree_model_node_is_root (tree_model, node) 673 || e_tree_model_node_get_children (tree_model, node, NULL) > 0) { 674 cairo_move_to ( 675 cr, 676 offset - INDENT_AMOUNT / 2, 677 height / 2); 678 cairo_line_to (cr, offset, height / 2); 679 } 680 681 if (visible_depth_of_node (ecell_view->e_table_model, row) != 0) { 682 cairo_move_to ( 683 cr, 684 offset - INDENT_AMOUNT / 2, height); 685 cairo_line_to ( 686 cr, 687 offset - INDENT_AMOUNT / 2, 688 e_tree_table_adapter_node_get_next 689 (tree_table_adapter, node) ? 0 : 690 height / 2); 691 } 692 693 /* now traverse back up to the root of the tree, checking at 694 * each level if the node has siblings, and drawing the 695 * correct vertical pipe for it's configuration. */ 696 node = e_tree_model_node_get_parent (tree_model, node); 697 depth = visible_depth_of_node (ecell_view->e_table_model, row) - 1; 698 offset -= INDENT_AMOUNT; 699 while (node && depth != 0) { 700 if (e_tree_table_adapter_node_get_next (tree_table_adapter, node)) { 701 cairo_move_to ( 702 cr, 703 offset - INDENT_AMOUNT / 2, 704 height); 705 cairo_line_to ( 706 cr, 707 offset - INDENT_AMOUNT / 2, 0); 708 } 709 node = e_tree_model_node_get_parent (tree_model, node); 710 depth--; 711 offset -= INDENT_AMOUNT; 712 } 713 } 714 715 /* now draw our icon if we're expandable */ 716 if (expandable) { 717 gboolean expanded; 718 GdkRectangle r; 719 gint exp_size = 0; 720 721 gtk_widget_style_get (GTK_WIDGET (gtk_widget_get_parent (GTK_WIDGET (tree_view->canvas))), "expander_size", &exp_size, NULL); 722 723 node = e_cell_tree_get_node (ecell_view->e_table_model, row); 724 expanded = e_tree_table_adapter_node_is_expanded (tree_table_adapter, node); 725 726 r.x = 0; 727 r.y = 0; 728 r.width = MIN (width, exp_size); 729 r.height = height; 730 731 draw_expander (tree_view, cr, expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED, GTK_STATE_NORMAL, &r); 732 } 733 734 cairo_stroke (cr); 735 736 cairo_translate (cr, subcell_offset, 0); 737 width -= subcell_offset; 738 } 739 740 cairo_restore (cr); 741 742 e_cell_print (tree_view->subcell_view, context, model_col, view_col, row, width, height); 743 } 744 745 static gdouble 746 ect_print_height (ECellView *ecell_view, 747 GtkPrintContext *context, 748 gint model_col, 749 gint view_col, 750 gint row, 751 gdouble width) 752 { 753 return 12; /* XXX */ 754 } 755 756 /* 757 * GObject::dispose method 758 */ 759 static void 760 ect_dispose (GObject *object) 761 { 762 ECellTree *ect = E_CELL_TREE (object); 763 764 /* destroy our subcell */ 765 if (ect->subcell) 766 g_object_unref (ect->subcell); 767 ect->subcell = NULL; 768 769 G_OBJECT_CLASS (e_cell_tree_parent_class)->dispose (object); 770 } 771 772 static void 773 e_cell_tree_class_init (ECellTreeClass *class) 774 { 775 GObjectClass *object_class = G_OBJECT_CLASS (class); 776 ECellClass *ecc = E_CELL_CLASS (class); 777 778 object_class->dispose = ect_dispose; 779 780 ecc->new_view = ect_new_view; 781 ecc->kill_view = ect_kill_view; 782 ecc->realize = ect_realize; 783 ecc->unrealize = ect_unrealize; 784 ecc->draw = ect_draw; 785 ecc->event = ect_event; 786 ecc->height = ect_height; 787 ecc->enter_edit = ect_enter_edit; 788 ecc->leave_edit = ect_leave_edit; 789 ecc->print = ect_print; 790 ecc->print_height = ect_print_height; 791 ecc->max_width = ect_max_width; 792 ecc->get_bg_color = ect_get_bg_color; 793 794 gal_a11y_e_cell_registry_add_cell_type (NULL, E_TYPE_CELL_TREE, gal_a11y_e_cell_tree_new); 795 } 796 797 static void 798 e_cell_tree_init (ECellTree *ect) 799 { 800 /* nothing to do */ 801 } 802 803 /** 804 * e_cell_tree_construct: 805 * @ect: the ECellTree we're constructing. 806 * @draw_lines: whether or not to draw the lines between parents/children/siblings. 807 * @subcell: the ECell to render to the right of the tree effects. 808 * 809 * Constructs an ECellTree. used by subclasses that need to 810 * initialize a nested ECellTree. See e_cell_tree_new() for more info. 811 * 812 **/ 813 void 814 e_cell_tree_construct (ECellTree *ect, 815 gboolean draw_lines, 816 ECell *subcell) 817 { 818 ect->subcell = subcell; 819 if (subcell) 820 g_object_ref_sink (subcell); 821 822 ect->draw_lines = draw_lines; 823 } 824 825 /** 826 * e_cell_tree_new: 827 * @draw_lines: whether or not to draw the lines between parents/children/siblings. 828 * @subcell: the ECell to render to the right of the tree effects. 829 * 830 * Creates a new ECell renderer that can be used to render tree 831 * effects that come from an ETreeModel. Various assumptions are made 832 * as to the fact that the ETableModel the ETable this cell is 833 * associated with is in fact an ETreeModel. The cell uses special 834 * columns to get at structural information (needed to draw the 835 * lines/icons. 836 * 837 * Return value: an ECell object that can be used to render trees. 838 **/ 839 ECell * 840 e_cell_tree_new (gboolean draw_lines, 841 ECell *subcell) 842 { 843 ECellTree *ect = g_object_new (E_TYPE_CELL_TREE, NULL); 844 845 e_cell_tree_construct (ect, draw_lines, subcell); 846 847 return (ECell *) ect; 848 }