evolution-3.6.4/widgets/table/e-table-group-container.c

Location Tool Test ID Function Issue
e-table-group-container.c:765:25 clang-analyzer Dereference of null pointer (loaded from variable 'col')
e-table-group-container.c:765:9 clang-analyzer Dereference of null pointer (loaded from variable 'row')
e-table-group-container.c:765:9 clang-analyzer Dereference of null pointer (loaded from variable 'row')
e-table-group-container.c:765:25 clang-analyzer Dereference of null pointer (loaded from variable 'col')
e-table-group-container.c:1288:3 clang-analyzer Access to field 'g_class' results in a dereference of a null pointer (loaded from variable 'etg')
e-table-group-container.c:1288:3 clang-analyzer Access to field 'g_class' results in a dereference of a null pointer (loaded from variable 'etg')
e-table-group-container.c:1403:5 clang-analyzer Access to field 'string' results in a dereference of a null pointer (loaded from variable 'child_node')
e-table-group-container.c:1403:5 clang-analyzer Access to field 'string' results in a dereference of a null pointer (loaded from variable 'child_node')
e-table-group-container.c:1409:5 clang-analyzer Access to field 'string' results in a dereference of a null pointer (loaded from variable 'child_node')
e-table-group-container.c:1409:5 clang-analyzer Access to field 'string' results in a dereference of a null pointer (loaded from variable 'child_node')
   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 <gtk/gtk.h>
  28 #include <gdk/gdkkeysyms.h>
  29 #include <libgnomecanvas/libgnomecanvas.h>
  30 
  31 #include "text/e-text.h"
  32 #include <glib/gi18n.h>
  33 #include "e-util/e-util.h"
  34 #include "misc/e-canvas-utils.h"
  35 #include "misc/e-canvas.h"
  36 #include "e-util/e-unicode.h"
  37 
  38 #include "e-table-defines.h"
  39 #include "e-table-group-container.h"
  40 #include "e-table-group-leaf.h"
  41 #include "e-table-item.h"
  42 #include "e-table-sorting-utils.h"
  43 
  44 #define TITLE_HEIGHT         16
  45 
  46 /* workaround for avoiding API breakage */
  47 #define etgc_get_type e_table_group_container_get_type
  48 G_DEFINE_TYPE (ETableGroupContainer, etgc, E_TYPE_TABLE_GROUP)
  49 
  50 enum {
  51 	PROP_0,
  52 	PROP_HEIGHT,
  53 	PROP_WIDTH,
  54 	PROP_MINIMUM_WIDTH,
  55 	PROP_FROZEN,
  56 	PROP_TABLE_ALTERNATING_ROW_COLORS,
  57 	PROP_TABLE_HORIZONTAL_DRAW_GRID,
  58 	PROP_TABLE_VERTICAL_DRAW_GRID,
  59 	PROP_TABLE_DRAW_FOCUS,
  60 	PROP_CURSOR_MODE,
  61 	PROP_SELECTION_MODEL,
  62 	PROP_LENGTH_THRESHOLD,
  63 	PROP_UNIFORM_ROW_HEIGHT
  64 };
  65 
  66 static EPrintable *
  67 etgc_get_printable (ETableGroup *etg);
  68 
  69 static void
  70 e_table_group_container_child_node_free (ETableGroupContainer *etgc,
  71                                          ETableGroupContainerChildNode *child_node)
  72 {
  73 	ETableGroup *etg = E_TABLE_GROUP (etgc);
  74 	ETableGroup *child = child_node->child;
  75 
  76 	g_object_run_dispose (G_OBJECT (child));
  77 	e_table_model_free_value (
  78 		etg->model, etgc->ecol->col_idx,
  79 		child_node->key);
  80 	g_free (child_node->string);
  81 	g_object_run_dispose (G_OBJECT (child_node->text));
  82 	g_object_run_dispose (G_OBJECT (child_node->rect));
  83 }
  84 
  85 static void
  86 e_table_group_container_list_free (ETableGroupContainer *etgc)
  87 {
  88 	ETableGroupContainerChildNode *child_node;
  89 	GList *list;
  90 
  91 	for (list = etgc->children; list; list = g_list_next (list)) {
  92 		child_node = (ETableGroupContainerChildNode *) list->data;
  93 		e_table_group_container_child_node_free (etgc, child_node);
  94 	}
  95 
  96 	g_list_free (etgc->children);
  97 	etgc->children = NULL;
  98 }
  99 
 100 static void
 101 etgc_dispose (GObject *object)
 102 {
 103 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (object);
 104 
 105 	if (etgc->children)
 106 		e_table_group_container_list_free (etgc);
 107 
 108 	if (etgc->font_desc)
 109 		pango_font_description_free (etgc->font_desc);
 110 	etgc->font_desc = NULL;
 111 
 112 	if (etgc->ecol)
 113 		g_object_unref (etgc->ecol);
 114 	etgc->ecol = NULL;
 115 
 116 	if (etgc->sort_info)
 117 		g_object_unref (etgc->sort_info);
 118 	etgc->sort_info = NULL;
 119 
 120 	if (etgc->selection_model)
 121 		g_object_unref (etgc->selection_model);
 122 	etgc->selection_model = NULL;
 123 
 124 	if (etgc->rect)
 125 		g_object_run_dispose (G_OBJECT (etgc->rect));
 126 	etgc->rect = NULL;
 127 
 128 	G_OBJECT_CLASS (etgc_parent_class)->dispose (object);
 129 }
 130 
 131 /**
 132  * e_table_group_container_construct
 133  * @parent: The %GnomeCanvasGroup to create a child of.
 134  * @etgc: The %ETableGroupContainer.
 135  * @full_header: The full header of the %ETable.
 136  * @header: The current header of the %ETable.
 137  * @model: The %ETableModel of the %ETable.
 138  * @sort_info: The %ETableSortInfo of the %ETable.
 139  * @n: Which grouping level this is (Starts at 0 and sends n + 1 to any child %ETableGroups.
 140  *
 141  * This routine constructs the new %ETableGroupContainer.
 142  */
 143 void
 144 e_table_group_container_construct (GnomeCanvasGroup *parent,
 145                                    ETableGroupContainer *etgc,
 146                                    ETableHeader *full_header,
 147                                    ETableHeader *header,
 148                                    ETableModel *model,
 149                                    ETableSortInfo *sort_info,
 150                                    gint n)
 151 {
 152 	ETableCol *col;
 153 	ETableSortColumn column = e_table_sort_info_grouping_get_nth (sort_info, n);
 154 	GtkWidget *widget;
 155 	GtkStyle *style;
 156 
 157 	col = e_table_header_get_column_by_col_idx (full_header, column.column);
 158 	if (col == NULL)
 159 		col = e_table_header_get_column (full_header, e_table_header_count (full_header) - 1);
 160 
 161 	e_table_group_construct (parent, E_TABLE_GROUP (etgc), full_header, header, model);
 162 	etgc->ecol = col;
 163 	g_object_ref (etgc->ecol);
 164 	etgc->sort_info = sort_info;
 165 	g_object_ref (etgc->sort_info);
 166 	etgc->n = n;
 167 	etgc->ascending = column.ascending;
 168 
 169 	widget = GTK_WIDGET (GNOME_CANVAS_ITEM (etgc)->canvas);
 170 	style = gtk_widget_get_style (widget);
 171 	etgc->font_desc = pango_font_description_copy (style->font_desc);
 172 
 173 	etgc->open = TRUE;
 174 }
 175 
 176 /**
 177  * e_table_group_container_new
 178  * @parent: The %GnomeCanvasGroup to create a child of.
 179  * @full_header: The full header of the %ETable.
 180  * @header: The current header of the %ETable.
 181  * @model: The %ETableModel of the %ETable.
 182  * @sort_info: The %ETableSortInfo of the %ETable.
 183  * @n: Which grouping level this is (Starts at 0 and sends n + 1 to any child %ETableGroups.
 184  *
 185  * %ETableGroupContainer is an %ETableGroup which groups by the nth
 186  * grouping of the %ETableSortInfo.  It creates %ETableGroups as
 187  * children.
 188  *
 189  * Returns: The new %ETableGroupContainer.
 190  */
 191 ETableGroup *
 192 e_table_group_container_new (GnomeCanvasGroup *parent,
 193                              ETableHeader *full_header,
 194                              ETableHeader *header,
 195                              ETableModel *model,
 196                              ETableSortInfo *sort_info,
 197                              gint n)
 198 {
 199 	ETableGroupContainer *etgc;
 200 
 201 	g_return_val_if_fail (parent != NULL, NULL);
 202 
 203 	etgc = g_object_new (E_TYPE_TABLE_GROUP_CONTAINER, NULL);
 204 
 205 	e_table_group_container_construct (
 206 		parent, etgc, full_header, header,
 207 		model, sort_info, n);
 208 	return E_TABLE_GROUP (etgc);
 209 }
 210 
 211 static gint
 212 etgc_event (GnomeCanvasItem *item,
 213             GdkEvent *event)
 214 {
 215 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (item);
 216 	gboolean return_val = TRUE;
 217 	gboolean change_focus = FALSE;
 218 	gboolean use_col = FALSE;
 219 	gint start_col = 0;
 220 	gint old_col;
 221 	EFocus direction = E_FOCUS_START;
 222 
 223 	switch (event->type) {
 224 	case GDK_KEY_PRESS:
 225 		if (event->key.keyval == GDK_KEY_Tab ||
 226 		    event->key.keyval == GDK_KEY_KP_Tab ||
 227 		    event->key.keyval == GDK_KEY_ISO_Left_Tab) {
 228 			change_focus = TRUE;
 229 			use_col      = TRUE;
 230 			start_col    = (event->key.state & GDK_SHIFT_MASK) ? -1 : 0;
 231 			direction    = (event->key.state & GDK_SHIFT_MASK) ? E_FOCUS_END : E_FOCUS_START;
 232 		} else if (event->key.keyval == GDK_KEY_Left ||
 233 			   event->key.keyval == GDK_KEY_KP_Left) {
 234 			change_focus = TRUE;
 235 			use_col      = TRUE;
 236 			start_col    = -1;
 237 			direction    = E_FOCUS_END;
 238 		} else if (event->key.keyval == GDK_KEY_Right ||
 239 			   event->key.keyval == GDK_KEY_KP_Right) {
 240 			change_focus = TRUE;
 241 			use_col   = TRUE;
 242 			start_col = 0;
 243 			direction = E_FOCUS_START;
 244 		} else if (event->key.keyval == GDK_KEY_Down ||
 245 			   event->key.keyval == GDK_KEY_KP_Down) {
 246 			change_focus = TRUE;
 247 			use_col      = FALSE;
 248 			direction    = E_FOCUS_START;
 249 		} else if (event->key.keyval == GDK_KEY_Up ||
 250 			   event->key.keyval == GDK_KEY_KP_Up) {
 251 			change_focus = TRUE;
 252 			use_col      = FALSE;
 253 			direction    = E_FOCUS_END;
 254 		} else if (event->key.keyval == GDK_KEY_Return ||
 255 			   event->key.keyval == GDK_KEY_KP_Enter) {
 256 			change_focus = TRUE;
 257 			use_col      = FALSE;
 258 			direction    = E_FOCUS_START;
 259 		}
 260 		if (change_focus) {
 261 			GList *list;
 262 			for (list = etgc->children; list; list = list->next) {
 263 				ETableGroupContainerChildNode *child_node;
 264 				ETableGroup                   *child;
 265 
 266 				child_node = (ETableGroupContainerChildNode *) list->data;
 267 				child      = child_node->child;
 268 
 269 				if (e_table_group_get_focus (child)) {
 270 					old_col = e_table_group_get_focus_column (child);
 271 					if (old_col == -1)
 272 						old_col = 0;
 273 					if (start_col == -1)
 274 						start_col = e_table_header_count (e_table_group_get_header (child)) - 1;
 275 
 276 					if (direction == E_FOCUS_END)
 277 						list = list->prev;
 278 					else
 279 						list = list->next;
 280 
 281 					if (list) {
 282 						child_node = (ETableGroupContainerChildNode *) list->data;
 283 						child = child_node->child;
 284 						if (use_col)
 285 							e_table_group_set_focus (child, direction, start_col);
 286 						else
 287 							e_table_group_set_focus (child, direction, old_col);
 288 						return 1;
 289 					} else {
 290 						return 0;
 291 					}
 292 				}
 293 			}
 294 			if (direction == E_FOCUS_END)
 295 				list = g_list_last (etgc->children);
 296 			else
 297 				list = etgc->children;
 298 			if (list) {
 299 				ETableGroupContainerChildNode *child_node;
 300 				ETableGroup                   *child;
 301 
 302 				child_node = (ETableGroupContainerChildNode *) list->data;
 303 				child = child_node->child;
 304 
 305 				if (start_col == -1)
 306 					start_col = e_table_header_count (e_table_group_get_header (child)) - 1;
 307 
 308 				e_table_group_set_focus (child, direction, start_col);
 309 				return 1;
 310 			}
 311 		}
 312 		return_val = FALSE;
 313 		break;
 314 	default:
 315 		return_val = FALSE;
 316 		break;
 317 	}
 318 	if (return_val == FALSE) {
 319 		if (GNOME_CANVAS_ITEM_CLASS (etgc_parent_class)->event)
 320 			return GNOME_CANVAS_ITEM_CLASS (etgc_parent_class)->event (item, event);
 321 	}
 322 	return return_val;
 323 
 324 }
 325 
 326 /* Realize handler for the text item */
 327 static void
 328 etgc_realize (GnomeCanvasItem *item)
 329 {
 330 	ETableGroupContainer *etgc;
 331 
 332 	if (GNOME_CANVAS_ITEM_CLASS (etgc_parent_class)->realize)
 333 		(* GNOME_CANVAS_ITEM_CLASS (etgc_parent_class)->realize) (item);
 334 
 335 	etgc = E_TABLE_GROUP_CONTAINER (item);
 336 
 337 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etgc));
 338 }
 339 
 340 /* Unrealize handler for the etgc item */
 341 static void
 342 etgc_unrealize (GnomeCanvasItem *item)
 343 {
 344 	if (GNOME_CANVAS_ITEM_CLASS (etgc_parent_class)->unrealize)
 345 		(* GNOME_CANVAS_ITEM_CLASS (etgc_parent_class)->unrealize) (item);
 346 }
 347 
 348 static void
 349 compute_text (ETableGroupContainer *etgc,
 350               ETableGroupContainerChildNode *child_node)
 351 {
 352 	gchar *text;
 353 
 354 	if (etgc->ecol->text) {
 355 		/* Translators: This text is used as a special row when an ETable
 356 		 * has turned on grouping on a column, which has set a title.
 357 		 * The first %s is replaced with a column title.
 358 		 * The second %s is replaced with an actual  group value.
 359 		 * Finally the %d is replaced with count of items in this group.
 360 		 * Example: "Family name: Smith (13 items)"
 361 		*/
 362 		text = g_strdup_printf (
 363 			ngettext (
 364 				"%s: %s (%d item)",
 365 				"%s: %s (%d items)",
 366 				child_node->count),
 367 			etgc->ecol->text, child_node->string,
 368 			(gint) child_node->count);
 369 	} else {
 370 		/* Translators: This text is used as a special row when an ETable
 371 		 * has turned on grouping on a column, which doesn't have set a title.
 372 		 * The %s is replaced with an actual group value.
 373 		 * The %d is replaced with count of items in this group.
 374 		 * Example: "Smith (13 items)"
 375 		*/
 376 		text = g_strdup_printf (
 377 			ngettext (
 378 				"%s (%d item)",
 379 				"%s (%d items)",
 380 				child_node->count),
 381 			child_node->string,
 382 			(gint) child_node->count);
 383 	}
 384 	gnome_canvas_item_set (
 385 		child_node->text,
 386 		"text", text,
 387 		NULL);
 388 	g_free (text);
 389 }
 390 
 391 static void
 392 child_cursor_change (ETableGroup *etg,
 393                      gint row,
 394                      ETableGroupContainer *etgc)
 395 {
 396 	e_table_group_cursor_change (E_TABLE_GROUP (etgc), row);
 397 }
 398 
 399 static void
 400 child_cursor_activated (ETableGroup *etg,
 401                         gint row,
 402                         ETableGroupContainer *etgc)
 403 {
 404 	e_table_group_cursor_activated (E_TABLE_GROUP (etgc), row);
 405 }
 406 
 407 static void
 408 child_double_click (ETableGroup *etg,
 409                     gint row,
 410                     gint col,
 411                     GdkEvent *event,
 412                     ETableGroupContainer *etgc)
 413 {
 414 	e_table_group_double_click (E_TABLE_GROUP (etgc), row, col, event);
 415 }
 416 
 417 static gboolean
 418 child_right_click (ETableGroup *etg,
 419                    gint row,
 420                    gint col,
 421                    GdkEvent *event,
 422                    ETableGroupContainer *etgc)
 423 {
 424 	return e_table_group_right_click (E_TABLE_GROUP (etgc), row, col, event);
 425 }
 426 
 427 static gboolean
 428 child_click (ETableGroup *etg,
 429              gint row,
 430              gint col,
 431              GdkEvent *event,
 432              ETableGroupContainer *etgc)
 433 {
 434 	return e_table_group_click (E_TABLE_GROUP (etgc), row, col, event);
 435 }
 436 
 437 static gboolean
 438 child_key_press (ETableGroup *etg,
 439                  gint row,
 440                  gint col,
 441                  GdkEvent *event,
 442                  ETableGroupContainer *etgc)
 443 {
 444 	return e_table_group_key_press (E_TABLE_GROUP (etgc), row, col, event);
 445 }
 446 
 447 static gboolean
 448 child_start_drag (ETableGroup *etg,
 449                   gint row,
 450                   gint col,
 451                   GdkEvent *event,
 452                   ETableGroupContainer *etgc)
 453 {
 454 	return e_table_group_start_drag (E_TABLE_GROUP (etgc), row, col, event);
 455 }
 456 
 457 static ETableGroupContainerChildNode *
 458 create_child_node (ETableGroupContainer *etgc,
 459                    gpointer val)
 460 {
 461 	ETableGroup *child;
 462 	ETableGroupContainerChildNode *child_node;
 463 	ETableGroup *etg = E_TABLE_GROUP (etgc);
 464 
 465 	child_node = g_new (ETableGroupContainerChildNode, 1);
 466 	child_node->rect = gnome_canvas_item_new (
 467 		GNOME_CANVAS_GROUP (etgc),
 468 		gnome_canvas_rect_get_type (),
 469 		"fill_color", "grey70",
 470 		"outline_color", "grey50",
 471 		NULL);
 472 	child_node->text = gnome_canvas_item_new (
 473 		GNOME_CANVAS_GROUP (etgc),
 474 		e_text_get_type (),
 475 		"fill_color", "black",
 476 		NULL);
 477 	child = e_table_group_new (
 478 		GNOME_CANVAS_GROUP (etgc), etg->full_header,
 479 		etg->header, etg->model, etgc->sort_info, etgc->n + 1);
 480 	gnome_canvas_item_set (
 481 		GNOME_CANVAS_ITEM (child),
 482 		"alternating_row_colors", etgc->alternating_row_colors,
 483 		"horizontal_draw_grid", etgc->horizontal_draw_grid,
 484 		"vertical_draw_grid", etgc->vertical_draw_grid,
 485 		"drawfocus", etgc->draw_focus,
 486 		"cursor_mode", etgc->cursor_mode,
 487 		"selection_model", etgc->selection_model,
 488 		"length_threshold", etgc->length_threshold,
 489 		"uniform_row_height", etgc->uniform_row_height,
 490 		"minimum_width", etgc->minimum_width - GROUP_INDENT,
 491 		NULL);
 492 
 493 	g_signal_connect (
 494 		child, "cursor_change",
 495 		G_CALLBACK (child_cursor_change), etgc);
 496 	g_signal_connect (
 497 		child, "cursor_activated",
 498 		G_CALLBACK (child_cursor_activated), etgc);
 499 	g_signal_connect (
 500 		child, "double_click",
 501 		G_CALLBACK (child_double_click), etgc);
 502 	g_signal_connect (
 503 		child, "right_click",
 504 		G_CALLBACK (child_right_click), etgc);
 505 	g_signal_connect (
 506 		child, "click",
 507 		G_CALLBACK (child_click), etgc);
 508 	g_signal_connect (
 509 		child, "key_press",
 510 		G_CALLBACK (child_key_press), etgc);
 511 	g_signal_connect (
 512 		child, "start_drag",
 513 		G_CALLBACK (child_start_drag), etgc);
 514 	child_node->child = child;
 515 	child_node->key = e_table_model_duplicate_value (etg->model, etgc->ecol->col_idx, val);
 516 	child_node->string = e_table_model_value_to_string (etg->model, etgc->ecol->col_idx, val);
 517 	child_node->count = 0;
 518 
 519 	return child_node;
 520 }
 521 
 522 static void
 523 etgc_add (ETableGroup *etg,
 524           gint row)
 525 {
 526 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
 527 	gpointer val = e_table_model_value_at (etg->model, etgc->ecol->col_idx, row);
 528 	GCompareDataFunc comp = etgc->ecol->compare;
 529 	gpointer cmp_cache = e_table_sorting_utils_create_cmp_cache ();
 530 	GList *list = etgc->children;
 531 	ETableGroup *child;
 532 	ETableGroupContainerChildNode *child_node;
 533 	gint i = 0;
 534 
 535 	for (; list; list = g_list_next (list), i++) {
 536 		gint comp_val;
 537 
 538 		child_node = list->data;
 539 		comp_val = (*comp)(child_node->key, val, cmp_cache);
 540 		if (comp_val == 0) {
 541 			e_table_sorting_utils_free_cmp_cache (cmp_cache);
 542 			child = child_node->child;
 543 			child_node->count++;
 544 			e_table_group_add (child, row);
 545 			compute_text (etgc, child_node);
 546 			return;
 547 		}
 548 		if ((comp_val > 0 && etgc->ascending) ||
 549 		    (comp_val < 0 && (!etgc->ascending)))
 550 			break;
 551 	}
 552 	e_table_sorting_utils_free_cmp_cache (cmp_cache);
 553 	child_node = create_child_node (etgc, val);
 554 	child = child_node->child;
 555 	child_node->count = 1;
 556 	e_table_group_add (child, row);
 557 
 558 	if (list)
 559 		etgc->children = g_list_insert (etgc->children, child_node, i);
 560 	else
 561 		etgc->children = g_list_append (etgc->children, child_node);
 562 
 563 	compute_text (etgc, child_node);
 564 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etgc));
 565 }
 566 
 567 static void
 568 etgc_add_array (ETableGroup *etg,
 569                 const gint *array,
 570                 gint count)
 571 {
 572 	gint i;
 573 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
 574 	gpointer lastval = NULL;
 575 	gint laststart = 0;
 576 	GCompareDataFunc comp = etgc->ecol->compare;
 577 	gpointer cmp_cache;
 578 	ETableGroupContainerChildNode *child_node;
 579 	ETableGroup *child;
 580 
 581 	if (count <= 0)
 582 		return;
 583 
 584 	e_table_group_container_list_free (etgc);
 585 	etgc->children = NULL;
 586 	cmp_cache = e_table_sorting_utils_create_cmp_cache ();
 587 
 588 	lastval = e_table_model_value_at (etg->model, etgc->ecol->col_idx, array[0]);
 589 
 590 	for (i = 1; i < count; i++) {
 591 		gpointer val = e_table_model_value_at (etg->model, etgc->ecol->col_idx, array[i]);
 592 		gint comp_val;
 593 
 594 		comp_val = (*comp)(lastval, val, cmp_cache);
 595 		if (comp_val != 0) {
 596 			child_node = create_child_node (etgc, lastval);
 597 			child = child_node->child;
 598 
 599 			e_table_group_add_array (child, array + laststart, i - laststart);
 600 			child_node->count = i - laststart;
 601 
 602 			etgc->children = g_list_append (etgc->children, child_node);
 603 			compute_text (etgc, child_node);
 604 			laststart = i;
 605 			lastval = val;
 606 		}
 607 	}
 608 
 609 	e_table_sorting_utils_free_cmp_cache (cmp_cache);
 610 
 611 	child_node = create_child_node (etgc, lastval);
 612 	child = child_node->child;
 613 
 614 	e_table_group_add_array (child, array + laststart, i - laststart);
 615 	child_node->count = i - laststart;
 616 
 617 	etgc->children = g_list_append (etgc->children, child_node);
 618 	compute_text (etgc, child_node);
 619 
 620 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etgc));
 621 }
 622 
 623 static void
 624 etgc_add_all (ETableGroup *etg)
 625 {
 626 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
 627 	ESorter *sorter = etgc->selection_model->sorter;
 628 	gint *array;
 629 	gint count;
 630 
 631 	e_sorter_get_sorted_to_model_array (sorter, &array, &count);
 632 
 633 	etgc_add_array (etg, array, count);
 634 }
 635 
 636 static gboolean
 637 etgc_remove (ETableGroup *etg,
 638              gint row)
 639 {
 640 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
 641 	GList *list;
 642 
 643 	for (list = etgc->children; list; list = g_list_next (list)) {
 644 		ETableGroupContainerChildNode *child_node = list->data;
 645 		ETableGroup                   *child = child_node->child;
 646 
 647 		if (e_table_group_remove (child, row)) {
 648 			child_node->count--;
 649 			if (child_node->count == 0) {
 650 				e_table_group_container_child_node_free (etgc, child_node);
 651 				etgc->children = g_list_remove (etgc->children, child_node);
 652 				g_free (child_node);
 653 			} else
 654 				compute_text (etgc, child_node);
 655 
 656 			e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etgc));
 657 
 658 			return TRUE;
 659 		}
 660 	}
 661 	return FALSE;
 662 }
 663 
 664 static gint
 665 etgc_row_count (ETableGroup *etg)
 666 {
 667 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
 668 	GList *list;
 669 	gint count = 0;
 670 	for (list = etgc->children; list; list = g_list_next (list)) {
 671 		ETableGroup *group = ((ETableGroupContainerChildNode *) list->data)->child;
 672 		gint this_count = e_table_group_row_count (group);
 673 		count += this_count;
 674 	}
 675 	return count;
 676 }
 677 
 678 static void
 679 etgc_increment (ETableGroup *etg,
 680                 gint position,
 681                 gint amount)
 682 {
 683 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
 684 	GList *list;
 685 
 686 	for (list = etgc->children; list; list = g_list_next (list))
 687 		e_table_group_increment (
 688 			((ETableGroupContainerChildNode *) list->data)->child,
 689 			position, amount);
 690 }
 691 
 692 static void
 693 etgc_decrement (ETableGroup *etg,
 694                 gint position,
 695                 gint amount)
 696 {
 697 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
 698 	GList *list;
 699 
 700 	for (list = etgc->children; list; list = g_list_next (list))
 701 		e_table_group_decrement (
 702 			((ETableGroupContainerChildNode *) list->data)->child,
 703 			position, amount);
 704 }
 705 
 706 static void
 707 etgc_set_focus (ETableGroup *etg,
 708                 EFocus direction,
 709                 gint view_col)
 710 {
 711 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
 712 	if (etgc->children) {
 713 		if (direction == E_FOCUS_END)
 714 			e_table_group_set_focus (
 715 				((ETableGroupContainerChildNode *) g_list_last (etgc->children)->data)->child,
 716 				direction, view_col);
 717 		else
 718 			e_table_group_set_focus (
 719 				((ETableGroupContainerChildNode *) etgc->children->data)->child,
 720 				direction, view_col);
 721 	}
 722 }
 723 
 724 static gint
 725 etgc_get_focus_column (ETableGroup *etg)
 726 {
 727 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
 728 	if (etgc->children) {
 729 		GList *list;
 730 		for (list = etgc->children; list; list = list->next) {
 731 			ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data;
 732 			ETableGroup *child = child_node->child;
 733 			if (e_table_group_get_focus (child)) {
 734 				return e_table_group_get_focus_column (child);
 735 			}
 736 		}
 737 	}
 738 	return 0;
 739 }
 740 
 741 static void
 742 etgc_compute_location (ETableGroup *etg,
 743                        gint *x,
 744                        gint *y,
 745                        gint *row,
 746                        gint *col)
 747 {
 748 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg);
 749 
 750 	if (row)
 751 		*row = -1;
 752 	if (col)
 753 		*col = -1;
 754 
 755 	*x -= GROUP_INDENT;
 756 	*y -= TITLE_HEIGHT;
 757 
 758 	if (*x >= 0 && *y >= 0 && etgc->children) {
 759 		GList *list;
 760 		for (list = etgc->children; list; list = list->next) {
 761 			ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data;
 762 			ETableGroup *child = child_node->child;
 763 
 764 			e_table_group_compute_location (child, x, y, row, col);
 765 			if ((*row != -1) && (*col != -1))
Dereference of null pointer (loaded from variable 'col')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Dereference of null pointer (loaded from variable 'row')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Dereference of null pointer (loaded from variable 'row')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Dereference of null pointer (loaded from variable 'col')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

766 return; 767 } 768 } 769 } 770 771 static void 772 etgc_get_mouse_over (ETableGroup *etg, 773 gint *row, 774 gint *col) 775 { 776 ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg); 777 778 if (row) 779 *row = -1; 780 if (col) 781 *col = -1; 782 783 if (etgc->children) { 784 gint row_plus = 0; 785 GList *list; 786 787 for (list = etgc->children; list; list = list->next) { 788 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 789 ETableGroup *child = child_node->child; 790 791 e_table_group_get_mouse_over (child, row, col); 792 793 if ((!row || *row != -1) && (!col || *col != -1)) { 794 if (row) 795 *row += row_plus; 796 return; 797 } 798 799 row_plus += e_table_group_row_count (child); 800 } 801 } 802 } 803 804 static void 805 etgc_get_cell_geometry (ETableGroup *etg, 806 gint *row, 807 gint *col, 808 gint *x, 809 gint *y, 810 gint *width, 811 gint *height) 812 { 813 ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg); 814 815 gint ypos; 816 817 ypos = 0; 818 819 if (etgc->children) { 820 GList *list; 821 for (list = etgc->children; list; list = list->next) { 822 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 823 ETableGroup *child = child_node->child; 824 gint thisy; 825 826 e_table_group_get_cell_geometry (child, row, col, x, &thisy, width, height); 827 ypos += thisy; 828 if ((*row == -1) || (*col == -1)) { 829 ypos += TITLE_HEIGHT; 830 *x += GROUP_INDENT; 831 *y = ypos; 832 return; 833 } 834 } 835 } 836 } 837 838 static void etgc_thaw (ETableGroup *etg) 839 { 840 e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (etg)); 841 } 842 843 static void 844 etgc_set_property (GObject *object, 845 guint property_id, 846 const GValue *value, 847 GParamSpec *pspec) 848 { 849 ETableGroup *etg = E_TABLE_GROUP (object); 850 ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (object); 851 GList *list; 852 853 switch (property_id) { 854 case PROP_FROZEN: 855 if (g_value_get_boolean (value)) 856 etg->frozen = TRUE; 857 else { 858 etg->frozen = FALSE; 859 etgc_thaw (etg); 860 } 861 break; 862 case PROP_MINIMUM_WIDTH: 863 case PROP_WIDTH: 864 etgc->minimum_width = g_value_get_double (value); 865 866 for (list = etgc->children; list; list = g_list_next (list)) { 867 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 868 g_object_set ( 869 child_node->child, 870 "minimum_width", etgc->minimum_width - GROUP_INDENT, 871 NULL); 872 } 873 break; 874 case PROP_LENGTH_THRESHOLD: 875 etgc->length_threshold = g_value_get_int (value); 876 for (list = etgc->children; list; list = g_list_next (list)) { 877 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 878 g_object_set ( 879 child_node->child, 880 "length_threshold", etgc->length_threshold, 881 NULL); 882 } 883 break; 884 case PROP_UNIFORM_ROW_HEIGHT: 885 etgc->uniform_row_height = g_value_get_boolean (value); 886 for (list = etgc->children; list; list = g_list_next (list)) { 887 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 888 g_object_set ( 889 child_node->child, 890 "uniform_row_height", etgc->uniform_row_height, 891 NULL); 892 } 893 break; 894 895 case PROP_SELECTION_MODEL: 896 if (etgc->selection_model) 897 g_object_unref (etgc->selection_model); 898 etgc->selection_model = E_SELECTION_MODEL (g_value_get_object (value)); 899 if (etgc->selection_model) 900 g_object_ref (etgc->selection_model); 901 for (list = etgc->children; list; list = g_list_next (list)) { 902 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 903 g_object_set ( 904 child_node->child, 905 "selection_model", etgc->selection_model, 906 NULL); 907 } 908 break; 909 910 case PROP_TABLE_ALTERNATING_ROW_COLORS: 911 etgc->alternating_row_colors = g_value_get_boolean (value); 912 for (list = etgc->children; list; list = g_list_next (list)) { 913 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 914 g_object_set ( 915 child_node->child, 916 "alternating_row_colors", etgc->alternating_row_colors, 917 NULL); 918 } 919 break; 920 921 case PROP_TABLE_HORIZONTAL_DRAW_GRID: 922 etgc->horizontal_draw_grid = g_value_get_boolean (value); 923 for (list = etgc->children; list; list = g_list_next (list)) { 924 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 925 g_object_set ( 926 child_node->child, 927 "horizontal_draw_grid", etgc->horizontal_draw_grid, 928 NULL); 929 } 930 break; 931 932 case PROP_TABLE_VERTICAL_DRAW_GRID: 933 etgc->vertical_draw_grid = g_value_get_boolean (value); 934 for (list = etgc->children; list; list = g_list_next (list)) { 935 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 936 g_object_set ( 937 child_node->child, 938 "vertical_draw_grid", etgc->vertical_draw_grid, 939 NULL); 940 } 941 break; 942 943 case PROP_TABLE_DRAW_FOCUS: 944 etgc->draw_focus = g_value_get_boolean (value); 945 for (list = etgc->children; list; list = g_list_next (list)) { 946 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 947 g_object_set ( 948 child_node->child, 949 "drawfocus", etgc->draw_focus, 950 NULL); 951 } 952 break; 953 954 case PROP_CURSOR_MODE: 955 etgc->cursor_mode = g_value_get_int (value); 956 for (list = etgc->children; list; list = g_list_next (list)) { 957 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 958 g_object_set ( 959 child_node->child, 960 "cursor_mode", etgc->cursor_mode, 961 NULL); 962 } 963 break; 964 default: 965 break; 966 } 967 } 968 969 static void 970 etgc_get_property (GObject *object, 971 guint property_id, 972 GValue *value, 973 GParamSpec *pspec) 974 { 975 ETableGroup *etg = E_TABLE_GROUP (object); 976 ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (object); 977 978 switch (property_id) { 979 case PROP_FROZEN: 980 g_value_set_boolean (value, etg->frozen); 981 break; 982 case PROP_HEIGHT: 983 g_value_set_double (value, etgc->height); 984 break; 985 case PROP_WIDTH: 986 g_value_set_double (value, etgc->width); 987 break; 988 case PROP_MINIMUM_WIDTH: 989 g_value_set_double (value, etgc->minimum_width); 990 break; 991 case PROP_UNIFORM_ROW_HEIGHT: 992 g_value_set_boolean (value, etgc->uniform_row_height); 993 break; 994 default: 995 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 996 break; 997 } 998 } 999 1000 static void 1001 etgc_class_init (ETableGroupContainerClass *class) 1002 { 1003 GnomeCanvasItemClass *item_class = GNOME_CANVAS_ITEM_CLASS (class); 1004 GObjectClass *object_class = G_OBJECT_CLASS (class); 1005 ETableGroupClass *e_group_class = E_TABLE_GROUP_CLASS (class); 1006 1007 object_class->dispose = etgc_dispose; 1008 object_class->set_property = etgc_set_property; 1009 object_class->get_property = etgc_get_property; 1010 1011 item_class->event = etgc_event; 1012 item_class->realize = etgc_realize; 1013 item_class->unrealize = etgc_unrealize; 1014 1015 e_group_class->add = etgc_add; 1016 e_group_class->add_array = etgc_add_array; 1017 e_group_class->add_all = etgc_add_all; 1018 e_group_class->remove = etgc_remove; 1019 e_group_class->increment = etgc_increment; 1020 e_group_class->decrement = etgc_decrement; 1021 e_group_class->row_count = etgc_row_count; 1022 e_group_class->set_focus = etgc_set_focus; 1023 e_group_class->get_focus_column = etgc_get_focus_column; 1024 e_group_class->get_printable = etgc_get_printable; 1025 e_group_class->compute_location = etgc_compute_location; 1026 e_group_class->get_mouse_over = etgc_get_mouse_over; 1027 e_group_class->get_cell_geometry = etgc_get_cell_geometry; 1028 1029 g_object_class_install_property ( 1030 object_class, 1031 PROP_TABLE_ALTERNATING_ROW_COLORS, 1032 g_param_spec_boolean ( 1033 "alternating_row_colors", 1034 "Alternating Row Colors", 1035 "Alternating Row Colors", 1036 FALSE, 1037 G_PARAM_WRITABLE)); 1038 1039 g_object_class_install_property ( 1040 object_class, 1041 PROP_TABLE_HORIZONTAL_DRAW_GRID, 1042 g_param_spec_boolean ( 1043 "horizontal_draw_grid", 1044 "Horizontal Draw Grid", 1045 "Horizontal Draw Grid", 1046 FALSE, 1047 G_PARAM_WRITABLE)); 1048 1049 g_object_class_install_property ( 1050 object_class, 1051 PROP_TABLE_VERTICAL_DRAW_GRID, 1052 g_param_spec_boolean ( 1053 "vertical_draw_grid", 1054 "Vertical Draw Grid", 1055 "Vertical Draw Grid", 1056 FALSE, 1057 G_PARAM_WRITABLE)); 1058 1059 g_object_class_install_property ( 1060 object_class, 1061 PROP_TABLE_DRAW_FOCUS, 1062 g_param_spec_boolean ( 1063 "drawfocus", 1064 "Draw focus", 1065 "Draw focus", 1066 FALSE, 1067 G_PARAM_WRITABLE)); 1068 1069 g_object_class_install_property ( 1070 object_class, 1071 PROP_CURSOR_MODE, 1072 g_param_spec_int ( 1073 "cursor_mode", 1074 "Cursor mode", 1075 "Cursor mode", 1076 E_CURSOR_LINE, 1077 E_CURSOR_SPREADSHEET, 1078 E_CURSOR_LINE, 1079 G_PARAM_WRITABLE)); 1080 1081 g_object_class_install_property ( 1082 object_class, 1083 PROP_SELECTION_MODEL, 1084 g_param_spec_object ( 1085 "selection_model", 1086 "Selection model", 1087 "Selection model", 1088 E_TYPE_SELECTION_MODEL, 1089 G_PARAM_WRITABLE)); 1090 1091 g_object_class_install_property ( 1092 object_class, 1093 PROP_LENGTH_THRESHOLD, 1094 g_param_spec_int ( 1095 "length_threshold", 1096 "Length Threshold", 1097 "Length Threshold", 1098 -1, G_MAXINT, 0, 1099 G_PARAM_READWRITE)); 1100 1101 g_object_class_install_property ( 1102 object_class, 1103 PROP_UNIFORM_ROW_HEIGHT, 1104 g_param_spec_boolean ( 1105 "uniform_row_height", 1106 "Uniform row height", 1107 "Uniform row height", 1108 FALSE, 1109 G_PARAM_READWRITE)); 1110 1111 g_object_class_install_property ( 1112 object_class, 1113 PROP_FROZEN, 1114 g_param_spec_boolean ( 1115 "frozen", 1116 "Frozen", 1117 "Frozen", 1118 FALSE, 1119 G_PARAM_READWRITE)); 1120 1121 g_object_class_install_property ( 1122 object_class, 1123 PROP_HEIGHT, 1124 g_param_spec_double ( 1125 "height", 1126 "Height", 1127 "Height", 1128 0.0, G_MAXDOUBLE, 0.0, 1129 G_PARAM_READWRITE)); 1130 1131 g_object_class_install_property ( 1132 object_class, 1133 PROP_WIDTH, 1134 g_param_spec_double ( 1135 "width", 1136 "Width", 1137 "Width", 1138 0.0, G_MAXDOUBLE, 0.0, 1139 G_PARAM_READWRITE)); 1140 1141 g_object_class_install_property ( 1142 object_class, 1143 PROP_MINIMUM_WIDTH, 1144 g_param_spec_double ( 1145 "minimum_width", 1146 "Minimum width", 1147 "Minimum Width", 1148 0.0, G_MAXDOUBLE, 0.0, 1149 G_PARAM_READWRITE)); 1150 } 1151 1152 static void 1153 etgc_reflow (GnomeCanvasItem *item, 1154 gint flags) 1155 { 1156 ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (item); 1157 gboolean frozen; 1158 1159 g_object_get ( 1160 etgc, 1161 "frozen", &frozen, 1162 NULL); 1163 1164 if (frozen) 1165 return; 1166 1167 if (item->flags & GNOME_CANVAS_ITEM_REALIZED) { 1168 gdouble running_height = 0; 1169 gdouble running_width = 0; 1170 gdouble old_height; 1171 gdouble old_width; 1172 1173 old_height = etgc->height; 1174 old_width = etgc->width; 1175 if (etgc->children == NULL) { 1176 } else { 1177 GList *list; 1178 gdouble extra_height = 0; 1179 gdouble item_height = 0; 1180 gdouble item_width = 0; 1181 1182 if (etgc->font_desc) { 1183 PangoContext *context; 1184 PangoFontMetrics *metrics; 1185 1186 context = gtk_widget_get_pango_context (GTK_WIDGET (item->canvas)); 1187 metrics = pango_context_get_metrics (context, etgc->font_desc, NULL); 1188 extra_height += 1189 PANGO_PIXELS (pango_font_metrics_get_ascent (metrics)) + 1190 PANGO_PIXELS (pango_font_metrics_get_descent (metrics)) + 1191 BUTTON_PADDING * 2; 1192 pango_font_metrics_unref (metrics); 1193 } 1194 1195 extra_height = MAX (extra_height, BUTTON_HEIGHT + BUTTON_PADDING * 2); 1196 1197 running_height = extra_height; 1198 1199 for (list = etgc->children; list; list = g_list_next (list)) { 1200 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 1201 ETableGroup *child = child_node->child; 1202 1203 g_object_get ( 1204 child, 1205 "width", &item_width, 1206 NULL); 1207 1208 if (item_width > running_width) 1209 running_width = item_width; 1210 } 1211 for (list = etgc->children; list; list = g_list_next (list)) { 1212 ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *) list->data; 1213 ETableGroup *child = child_node->child; 1214 g_object_get ( 1215 child, 1216 "height", &item_height, 1217 NULL); 1218 1219 e_canvas_item_move_absolute ( 1220 GNOME_CANVAS_ITEM (child_node->text), 1221 GROUP_INDENT, 1222 running_height - GROUP_INDENT - BUTTON_PADDING); 1223 1224 e_canvas_item_move_absolute ( 1225 GNOME_CANVAS_ITEM (child), 1226 GROUP_INDENT, 1227 running_height); 1228 1229 gnome_canvas_item_set ( 1230 GNOME_CANVAS_ITEM (child_node->rect), 1231 "x1", (gdouble) 0, 1232 "x2", (gdouble) running_width + GROUP_INDENT, 1233 "y1", (gdouble) running_height - extra_height, 1234 "y2", (gdouble) running_height + item_height, 1235 NULL); 1236 1237 running_height += item_height + extra_height; 1238 } 1239 running_height -= extra_height; 1240 } 1241 if (running_height != old_height || running_width != old_width) { 1242 etgc->height = running_height; 1243 etgc->width = running_width; 1244 e_canvas_item_request_parent_reflow (item); 1245 } 1246 } 1247 } 1248 1249 static void 1250 etgc_init (ETableGroupContainer *container) 1251 { 1252 container->children = NULL; 1253 1254 e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM (container), etgc_reflow); 1255 1256 container->alternating_row_colors = 1; 1257 container->horizontal_draw_grid = 1; 1258 container->vertical_draw_grid = 1; 1259 container->draw_focus = 1; 1260 container->cursor_mode = E_CURSOR_SIMPLE; 1261 container->length_threshold = -1; 1262 container->selection_model = NULL; 1263 container->uniform_row_height = FALSE; 1264 } 1265 1266 void 1267 e_table_group_apply_to_leafs (ETableGroup *etg, 1268 ETableGroupLeafFn fn, 1269 gpointer closure) 1270 { 1271 if (E_IS_TABLE_GROUP_CONTAINER (etg)) { 1272 ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg); 1273 GList *list; 1274 1275 /* Protect from unrefs in the callback functions */ 1276 g_object_ref (etg); 1277 1278 for (list = etgc->children; list; list = list->next) { 1279 ETableGroupContainerChildNode *child_node = list->data; 1280 1281 e_table_group_apply_to_leafs (child_node->child, fn, closure); 1282 } 1283 1284 g_object_unref (etg); 1285 } else if (E_IS_TABLE_GROUP_LEAF (etg)) { 1286 (*fn) (E_TABLE_GROUP_LEAF (etg)->item, closure); 1287 } else { 1288 g_error (
Access to field 'g_class' results in a dereference of a null pointer (loaded from variable 'etg')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Access to field 'g_class' results in a dereference of a null pointer (loaded from variable 'etg')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

1289 "Unknown ETableGroup found: %s", 1290 g_type_name (G_TYPE_FROM_INSTANCE (etg))); 1291 } 1292 } 1293 1294 typedef struct { 1295 ETableGroupContainer *etgc; 1296 GList *child; 1297 EPrintable *child_printable; 1298 } ETGCPrintContext; 1299 1300 #define CHECK(x) if((x) == -1) return -1; 1301 1302 #if 0 1303 static gint 1304 gp_draw_rect (GtkPrintContext *context, 1305 gdouble x, 1306 gdouble y, 1307 gdouble width, 1308 gdouble height) 1309 { 1310 cairo_t *cr; 1311 cr = gtk_print_context_get_cairo_context (context); 1312 cairo_move_to (cr, x, y); 1313 cairo_rectangle (cr, x, y, x + width, y + height); 1314 cairo_fill (cr); 1315 } 1316 #endif 1317 1318 #define TEXT_HEIGHT (12) 1319 #define TEXT_AREA_HEIGHT (TEXT_HEIGHT + 4) 1320 1321 static void 1322 e_table_group_container_print_page (EPrintable *ep, 1323 GtkPrintContext *context, 1324 gdouble width, 1325 gdouble height, 1326 gboolean quantize, 1327 ETGCPrintContext *groupcontext) 1328 { 1329 cairo_t *cr = NULL; 1330 GtkPageSetup *setup; 1331 gdouble yd; 1332 gdouble page_height, page_margin; 1333 gdouble child_height, child_margin = 0; 1334 ETableGroupContainerChildNode *child_node; 1335 GList *child; 1336 EPrintable *child_printable; 1337 gchar *string; 1338 PangoLayout *layout; 1339 PangoFontDescription *desc; 1340 1341 child_printable = groupcontext->child_printable; 1342 child = groupcontext->child; 1343 setup = gtk_print_context_get_page_setup (context); 1344 page_height = gtk_page_setup_get_page_height (setup, GTK_UNIT_POINTS); 1345 page_margin = gtk_page_setup_get_bottom_margin (setup, GTK_UNIT_POINTS) + gtk_page_setup_get_top_margin (setup, GTK_UNIT_POINTS); 1346 yd = page_height - page_margin; 1347 1348 if (child_printable) { 1349 if (child) 1350 child_node = child->data; 1351 else 1352 child_node = NULL; 1353 g_object_ref (child_printable); 1354 } else { 1355 if (!child) { 1356 return; 1357 } else { 1358 child_node = child->data; 1359 child_printable = e_table_group_get_printable (child_node->child); 1360 if (child_printable) 1361 g_object_ref (child_printable); 1362 e_printable_reset (child_printable); 1363 } 1364 } 1365 1366 layout = gtk_print_context_create_pango_layout (context); 1367 1368 desc = pango_font_description_new (); 1369 pango_font_description_set_family_static (desc, "Helvetica"); 1370 pango_font_description_set_size (desc, TEXT_HEIGHT); 1371 pango_layout_set_font_description (layout, desc); 1372 pango_font_description_free (desc); 1373 1374 while (1) { 1375 child_height = e_printable_height (child_printable, context, width,yd, quantize); 1376 if (child_height < 0) 1377 child_height = -child_height; 1378 if (cr && yd < 2 * TEXT_AREA_HEIGHT + 20 + child_height) { 1379 cairo_show_page (cr); 1380 cairo_translate (cr, -2 * TEXT_AREA_HEIGHT, -TEXT_AREA_HEIGHT); 1381 break; 1382 } 1383 1384 cr = gtk_print_context_get_cairo_context (context); 1385 cairo_save (cr); 1386 cairo_rectangle (cr, 0.0, 0.0, width, TEXT_AREA_HEIGHT); 1387 cairo_rectangle (cr, 0.0, 0.0, 2 * TEXT_AREA_HEIGHT, child_height + 2 * TEXT_AREA_HEIGHT); 1388 cairo_set_source_rgb (cr, .7, .7, .7); 1389 cairo_fill (cr); 1390 cairo_restore (cr); 1391 child_margin = TEXT_AREA_HEIGHT; 1392 1393 cairo_save (cr); 1394 cairo_rectangle (cr, 2 * TEXT_AREA_HEIGHT, TEXT_AREA_HEIGHT, width - 2 * TEXT_AREA_HEIGHT, TEXT_AREA_HEIGHT); 1395 cairo_clip (cr); 1396 cairo_restore (cr); 1397 1398 cairo_move_to (cr, 0, 0); 1399 if (groupcontext->etgc->ecol->text) 1400 string = g_strdup_printf ( 1401 "%s : %s (%d item%s)", 1402 groupcontext->etgc->ecol->text, 1403 child_node->string,
Access to field 'string' results in a dereference of a null pointer (loaded from variable 'child_node')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Access to field 'string' results in a dereference of a null pointer (loaded from variable 'child_node')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

1404 (gint) child_node->count, 1405 child_node->count == 1 ? "" : "s"); 1406 else 1407 string = g_strdup_printf ( 1408 "%s (%d item%s)", 1409 child_node->string,
Access to field 'string' results in a dereference of a null pointer (loaded from variable 'child_node')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Access to field 'string' results in a dereference of a null pointer (loaded from variable 'child_node')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

1410 (gint) child_node->count, 1411 child_node->count == 1 ? "" : "s"); 1412 pango_layout_set_text (layout, string, -1); 1413 pango_cairo_show_layout (cr, layout); 1414 g_free (string); 1415 1416 cairo_translate (cr, 2 * TEXT_AREA_HEIGHT, TEXT_AREA_HEIGHT); 1417 cairo_move_to (cr, 0, 0); 1418 cairo_save (cr); 1419 cairo_rectangle (cr, 0, child_margin, width - 2 * TEXT_AREA_HEIGHT, child_height + child_margin + 20); 1420 cairo_clip (cr); 1421 1422 e_printable_print_page (child_printable, context, width - 2 * TEXT_AREA_HEIGHT, child_margin, quantize); 1423 yd -= child_height + TEXT_AREA_HEIGHT; 1424 1425 if (e_printable_data_left (child_printable)) { 1426 cairo_restore (cr); 1427 cairo_translate (cr, -2 * TEXT_AREA_HEIGHT, -TEXT_AREA_HEIGHT); 1428 break; 1429 } 1430 1431 child = child->next; 1432 if (!child) { 1433 child_printable = NULL; 1434 break; 1435 } 1436 1437 child_node = child->data; 1438 if (child_printable) 1439 g_object_unref (child_printable); 1440 1441 child_printable = e_table_group_get_printable (child_node->child); 1442 cairo_restore (cr); 1443 cairo_translate (cr, -2 * TEXT_AREA_HEIGHT, child_height + child_margin + 20); 1444 1445 if (child_printable) 1446 g_object_ref (child_printable); 1447 e_printable_reset (child_printable); 1448 } 1449 if (groupcontext->child_printable) 1450 g_object_unref (groupcontext->child_printable); 1451 groupcontext->child_printable = child_printable; 1452 groupcontext->child = child; 1453 1454 g_object_unref (layout); 1455 } 1456 1457 static gboolean 1458 e_table_group_container_data_left (EPrintable *ep, 1459 ETGCPrintContext *groupcontext) 1460 { 1461 g_signal_stop_emission_by_name (ep, "data_left"); 1462 return groupcontext->child != NULL; 1463 } 1464 1465 static void 1466 e_table_group_container_reset (EPrintable *ep, 1467 ETGCPrintContext *groupcontext) 1468 { 1469 groupcontext->child = groupcontext->etgc->children; 1470 if (groupcontext->child_printable) 1471 g_object_unref (groupcontext->child_printable); 1472 groupcontext->child_printable = NULL; 1473 } 1474 1475 static gdouble 1476 e_table_group_container_height (EPrintable *ep, 1477 GtkPrintContext *context, 1478 gdouble width, 1479 gdouble max_height, 1480 gboolean quantize, 1481 ETGCPrintContext *groupcontext) 1482 { 1483 gdouble height = 0; 1484 gdouble child_height; 1485 gdouble yd = max_height; 1486 ETableGroupContainerChildNode *child_node; 1487 GList *child; 1488 EPrintable *child_printable; 1489 1490 child_printable = groupcontext->child_printable; 1491 child = groupcontext->child; 1492 1493 if (child_printable) 1494 g_object_ref (child_printable); 1495 else { 1496 if (!child) { 1497 g_signal_stop_emission_by_name (ep, "height"); 1498 return 0; 1499 } else { 1500 child_node = child->data; 1501 child_printable = e_table_group_get_printable (child_node->child); 1502 if (child_printable) 1503 g_object_ref (child_printable); 1504 e_printable_reset (child_printable); 1505 } 1506 } 1507 1508 if (yd != -1 && yd < TEXT_AREA_HEIGHT) 1509 return 0; 1510 1511 while (1) { 1512 child_height = e_printable_height (child_printable, context, width - 36, yd - (yd == -1 ? 0 : TEXT_AREA_HEIGHT), quantize); 1513 1514 height -= child_height + TEXT_AREA_HEIGHT; 1515 1516 if (yd != -1) { 1517 if (!e_printable_will_fit (child_printable, context, width - 36, yd - (yd == -1 ? 0 : TEXT_AREA_HEIGHT), quantize)) { 1518 break; 1519 } 1520 1521 yd += child_height + TEXT_AREA_HEIGHT; 1522 } 1523 1524 child = child->next; 1525 if (!child) { 1526 break; 1527 } 1528 1529 child_node = child->data; 1530 if (child_printable) 1531 g_object_unref (child_printable); 1532 child_printable = e_table_group_get_printable (child_node->child); 1533 if (child_printable) 1534 g_object_ref (child_printable); 1535 e_printable_reset (child_printable); 1536 } 1537 if (child_printable) 1538 g_object_unref (child_printable); 1539 g_signal_stop_emission_by_name (ep, "height"); 1540 return height; 1541 } 1542 1543 static gboolean 1544 e_table_group_container_will_fit (EPrintable *ep, 1545 GtkPrintContext *context, 1546 gdouble width, 1547 gdouble max_height, 1548 gboolean quantize, 1549 ETGCPrintContext *groupcontext) 1550 { 1551 gboolean will_fit = TRUE; 1552 gdouble child_height; 1553 gdouble yd = max_height; 1554 ETableGroupContainerChildNode *child_node; 1555 GList *child; 1556 EPrintable *child_printable; 1557 1558 child_printable = groupcontext->child_printable; 1559 child = groupcontext->child; 1560 1561 if (child_printable) 1562 g_object_ref (child_printable); 1563 else { 1564 if (!child) { 1565 g_signal_stop_emission_by_name (ep, "will_fit"); 1566 return will_fit; 1567 } else { 1568 child_node = child->data; 1569 child_printable = e_table_group_get_printable (child_node->child); 1570 if (child_printable) 1571 g_object_ref (child_printable); 1572 e_printable_reset (child_printable); 1573 } 1574 } 1575 1576 if (yd != -1 && yd < TEXT_AREA_HEIGHT) 1577 will_fit = FALSE; 1578 else { 1579 while (1) { 1580 child_height = e_printable_height (child_printable, context, width - 36, yd - (yd == -1 ? 0 : TEXT_AREA_HEIGHT), quantize); 1581 1582 if (yd != -1) { 1583 if (!e_printable_will_fit (child_printable, context, width - 36, yd - (yd == -1 ? 0 : TEXT_AREA_HEIGHT), quantize)) { 1584 will_fit = FALSE; 1585 break; 1586 } 1587 1588 yd += child_height + TEXT_AREA_HEIGHT; 1589 } 1590 1591 child = child->next; 1592 if (!child) { 1593 break; 1594 } 1595 1596 child_node = child->data; 1597 if (child_printable) 1598 g_object_unref (child_printable); 1599 child_printable = e_table_group_get_printable (child_node->child); 1600 if (child_printable) 1601 g_object_ref (child_printable); 1602 e_printable_reset (child_printable); 1603 } 1604 } 1605 1606 if (child_printable) 1607 g_object_unref (child_printable); 1608 1609 g_signal_stop_emission_by_name (ep, "will_fit"); 1610 return will_fit; 1611 } 1612 1613 static void 1614 e_table_group_container_printable_destroy (gpointer data, 1615 GObject *where_object_was) 1616 1617 { 1618 ETGCPrintContext *groupcontext = data; 1619 1620 g_object_unref (groupcontext->etgc); 1621 if (groupcontext->child_printable) 1622 g_object_ref (groupcontext->child_printable); 1623 g_free (groupcontext); 1624 } 1625 1626 static EPrintable * 1627 etgc_get_printable (ETableGroup *etg) 1628 { 1629 ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER (etg); 1630 EPrintable *printable = e_printable_new (); 1631 ETGCPrintContext *groupcontext; 1632 1633 groupcontext = g_new (ETGCPrintContext, 1); 1634 groupcontext->etgc = etgc; 1635 g_object_ref (etgc); 1636 groupcontext->child = etgc->children; 1637 groupcontext->child_printable = NULL; 1638 1639 g_signal_connect ( 1640 printable, "print_page", 1641 G_CALLBACK (e_table_group_container_print_page), 1642 groupcontext); 1643 g_signal_connect ( 1644 printable, "data_left", 1645 G_CALLBACK (e_table_group_container_data_left), 1646 groupcontext); 1647 g_signal_connect ( 1648 printable, "reset", 1649 G_CALLBACK (e_table_group_container_reset), 1650 groupcontext); 1651 g_signal_connect ( 1652 printable, "height", 1653 G_CALLBACK (e_table_group_container_height), 1654 groupcontext); 1655 g_signal_connect ( 1656 printable, "will_fit", 1657 G_CALLBACK (e_table_group_container_will_fit), 1658 groupcontext); 1659 g_object_weak_ref ( 1660 G_OBJECT (printable), 1661 e_table_group_container_printable_destroy, 1662 groupcontext); 1663 1664 return printable; 1665 }