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

Location Tool Test ID Function Issue
e-tree.c:983:17 clang-analyzer The left operand of '==' is a garbage value
e-tree.c:983:17 clang-analyzer The left operand of '==' is a garbage value
e-tree.c:1002:17 clang-analyzer The left operand of '==' is a garbage value
e-tree.c:1002:17 clang-analyzer The left operand of '==' is a garbage value
e-tree.c:2685:6 clang-analyzer The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
e-tree.c:2685:6 clang-analyzer The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
e-tree.c:2689:5 clang-analyzer The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
e-tree.c:2689:5 clang-analyzer The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
e-tree.c:3094:10 clang-analyzer The left operand of '!=' is a garbage value
e-tree.c:3094:10 clang-analyzer The left operand of '!=' is a garbage value
e-tree.c:3215:9 clang-analyzer Function call argument is an uninitialized value
e-tree.c:3215:9 clang-analyzer Function call argument is an uninitialized value
e-tree.c:3411:9 clang-analyzer Function call argument is an uninitialized value
e-tree.c:3411:9 clang-analyzer Function call argument is an uninitialized value
e-tree.c:3472:9 clang-analyzer Function call argument is an uninitialized value
e-tree.c:3472:9 clang-analyzer Function call argument is an uninitialized value
   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 <stdlib.h>
  28 #include <stdio.h>
  29 #include <string.h>
  30 
  31 #include <gdk/gdkkeysyms.h>
  32 #include <gtk/gtk.h>
  33 #include <libgnomecanvas/libgnomecanvas.h>
  34 
  35 #include "gal-a11y-e-tree.h"
  36 #include <glib/gi18n.h>
  37 #include "e-util/e-util.h"
  38 #include "misc/e-canvas.h"
  39 #include "misc/e-canvas-utils.h"
  40 #include "misc/e-canvas-background.h"
  41 #include "text/e-text.h"
  42 
  43 #include "e-table-column-specification.h"
  44 #include "e-table-header-item.h"
  45 #include "e-table-header.h"
  46 #include "e-table-item.h"
  47 #include "e-table-sort-info.h"
  48 #include "e-table-utils.h"
  49 #ifdef E_TREE_USE_TREE_SELECTION
  50 #include "e-tree-selection-model.h"
  51 #else
  52 #include "e-table-selection-model.h"
  53 #endif
  54 #include "e-tree.h"
  55 #include "e-tree-table-adapter.h"
  56 
  57 #define COLUMN_HEADER_HEIGHT 16
  58 
  59 #define d(x)
  60 
  61 #define E_TREE_GET_PRIVATE(obj) \
  62 	(G_TYPE_INSTANCE_GET_PRIVATE \
  63 	((obj), E_TYPE_TREE, ETreePrivate))
  64 
  65 enum {
  66 	CURSOR_CHANGE,
  67 	CURSOR_ACTIVATED,
  68 	SELECTION_CHANGE,
  69 	DOUBLE_CLICK,
  70 	RIGHT_CLICK,
  71 	CLICK,
  72 	KEY_PRESS,
  73 	START_DRAG,
  74 	STATE_CHANGE,
  75 	WHITE_SPACE_EVENT,
  76 
  77 	CUT_CLIPBOARD,
  78 	COPY_CLIPBOARD,
  79 	PASTE_CLIPBOARD,
  80 	SELECT_ALL,
  81 
  82 	TREE_DRAG_BEGIN,
  83 	TREE_DRAG_END,
  84 	TREE_DRAG_DATA_GET,
  85 	TREE_DRAG_DATA_DELETE,
  86 
  87 	TREE_DRAG_LEAVE,
  88 	TREE_DRAG_MOTION,
  89 	TREE_DRAG_DROP,
  90 	TREE_DRAG_DATA_RECEIVED,
  91 
  92 	LAST_SIGNAL
  93 };
  94 
  95 enum {
  96 	PROP_0,
  97 	PROP_LENGTH_THRESHOLD,
  98 	PROP_HORIZONTAL_DRAW_GRID,
  99 	PROP_VERTICAL_DRAW_GRID,
 100 	PROP_DRAW_FOCUS,
 101 	PROP_ETTA,
 102 	PROP_UNIFORM_ROW_HEIGHT,
 103 	PROP_ALWAYS_SEARCH,
 104 	PROP_HADJUSTMENT,
 105 	PROP_VADJUSTMENT,
 106 	PROP_HSCROLL_POLICY,
 107 	PROP_VSCROLL_POLICY
 108 };
 109 
 110 enum {
 111 	ET_SCROLL_UP = 1 << 0,
 112 	ET_SCROLL_DOWN = 1 << 1,
 113 	ET_SCROLL_LEFT = 1 << 2,
 114 	ET_SCROLL_RIGHT = 1 << 3
 115 };
 116 
 117 struct _ETreePrivate {
 118 	ETreeModel *model;
 119 	ETreeTableAdapter *etta;
 120 
 121 	ETableHeader *full_header, *header;
 122 
 123 	guint structure_change_id, expansion_change_id;
 124 
 125 	ETableSortInfo *sort_info;
 126 	ESorter   *sorter;
 127 
 128 	guint sort_info_change_id, group_info_change_id;
 129 
 130 	ESelectionModel *selection;
 131 	ETableSpecification *spec;
 132 
 133 	ETableSearch     *search;
 134 
 135 	ETableCol        *current_search_col;
 136 
 137 	guint	  search_search_id;
 138 	guint	  search_accept_id;
 139 
 140 	gint reflow_idle_id;
 141 	gint scroll_idle_id;
 142 	gint hover_idle_id;
 143 
 144 	gboolean show_cursor_after_reflow;
 145 
 146 	gint table_model_change_id;
 147 	gint table_row_change_id;
 148 	gint table_cell_change_id;
 149 	gint table_rows_delete_id;
 150 
 151 	GnomeCanvasItem *info_text;
 152 	guint info_text_resize_id;
 153 
 154 	GnomeCanvas *header_canvas, *table_canvas;
 155 
 156 	GnomeCanvasItem *header_item, *root;
 157 
 158 	GnomeCanvasItem *white_item;
 159 	GnomeCanvasItem *item;
 160 
 161 	gint length_threshold;
 162 
 163 	/*
 164 	 * Configuration settings
 165 	 */
 166 	guint alternating_row_colors : 1;
 167 	guint horizontal_draw_grid : 1;
 168 	guint vertical_draw_grid : 1;
 169 	guint draw_focus : 1;
 170 	guint row_selection_active : 1;
 171 
 172 	guint horizontal_scrolling : 1;
 173 
 174 	guint scroll_direction : 4;
 175 
 176 	guint do_drag : 1;
 177 
 178 	guint uniform_row_height : 1;
 179 
 180 	guint search_col_set : 1;
 181 	guint always_search : 1;
 182 
 183 	ECursorMode cursor_mode;
 184 
 185 	gint drop_row;
 186 	ETreePath drop_path;
 187 	gint drop_col;
 188 
 189 	GnomeCanvasItem *drop_highlight;
 190 	gint last_drop_x;
 191 	gint last_drop_y;
 192 	gint last_drop_time;
 193 	GdkDragContext *last_drop_context;
 194 
 195 	gint hover_x;
 196 	gint hover_y;
 197 
 198 	gint drag_row;
 199 	ETreePath drag_path;
 200 	gint drag_col;
 201 	ETreeDragSourceSite *site;
 202 
 203 	GList *expanded_list;
 204 
 205 	gboolean state_changed;
 206 	guint state_change_freeze;
 207 
 208 	gboolean is_dragging;
 209 };
 210 
 211 static guint et_signals[LAST_SIGNAL] = { 0, };
 212 
 213 static void et_grab_focus (GtkWidget *widget);
 214 
 215 static void et_drag_begin (GtkWidget *widget,
 216 			   GdkDragContext *context,
 217 			   ETree *et);
 218 static void et_drag_end (GtkWidget *widget,
 219 			 GdkDragContext *context,
 220 			 ETree *et);
 221 static void et_drag_data_get (GtkWidget *widget,
 222 			     GdkDragContext *context,
 223 			     GtkSelectionData *selection_data,
 224 			     guint info,
 225 			     guint time,
 226 			     ETree *et);
 227 static void et_drag_data_delete (GtkWidget *widget,
 228 				GdkDragContext *context,
 229 				ETree *et);
 230 
 231 static void et_drag_leave (GtkWidget *widget,
 232 			  GdkDragContext *context,
 233 			  guint time,
 234 			  ETree *et);
 235 static gboolean et_drag_motion (GtkWidget *widget,
 236 			       GdkDragContext *context,
 237 			       gint x,
 238 			       gint y,
 239 			       guint time,
 240 			       ETree *et);
 241 static gboolean et_drag_drop (GtkWidget *widget,
 242 			     GdkDragContext *context,
 243 			     gint x,
 244 			     gint y,
 245 			     guint time,
 246 			     ETree *et);
 247 static void et_drag_data_received (GtkWidget *widget,
 248 				  GdkDragContext *context,
 249 				  gint x,
 250 				  gint y,
 251 				  GtkSelectionData *selection_data,
 252 				  guint info,
 253 				  guint time,
 254 				  ETree *et);
 255 
 256 static void scroll_off (ETree *et);
 257 static void scroll_on (ETree *et, guint scroll_direction);
 258 static void hover_off (ETree *et);
 259 static void hover_on (ETree *et, gint x, gint y);
 260 static void context_destroyed (gpointer data, GObject *ctx);
 261 
 262 G_DEFINE_TYPE_WITH_CODE (ETree, e_tree, GTK_TYPE_TABLE,
 263 			 G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
 264 
 265 static void
 266 et_disconnect_from_etta (ETree *et)
 267 {
 268 	if (et->priv->table_model_change_id != 0)
 269 		g_signal_handler_disconnect (
 270 			et->priv->etta,
 271 			et->priv->table_model_change_id);
 272 	if (et->priv->table_row_change_id != 0)
 273 		g_signal_handler_disconnect (
 274 			et->priv->etta,
 275 			et->priv->table_row_change_id);
 276 	if (et->priv->table_cell_change_id != 0)
 277 		g_signal_handler_disconnect (
 278 			et->priv->etta,
 279 			et->priv->table_cell_change_id);
 280 	if (et->priv->table_rows_delete_id != 0)
 281 		g_signal_handler_disconnect (
 282 			et->priv->etta,
 283 			et->priv->table_rows_delete_id);
 284 
 285 	et->priv->table_model_change_id = 0;
 286 	et->priv->table_row_change_id = 0;
 287 	et->priv->table_cell_change_id = 0;
 288 	et->priv->table_rows_delete_id = 0;
 289 }
 290 
 291 static void
 292 clear_current_search_col (ETree *et)
 293 {
 294 	et->priv->search_col_set = FALSE;
 295 }
 296 
 297 static ETableCol *
 298 current_search_col (ETree *et)
 299 {
 300 	if (!et->priv->search_col_set) {
 301 		et->priv->current_search_col =
 302 			e_table_util_calculate_current_search_col (
 303 				et->priv->header,
 304 				et->priv->full_header,
 305 				et->priv->sort_info,
 306 				et->priv->always_search);
 307 		et->priv->search_col_set = TRUE;
 308 	}
 309 
 310 	return et->priv->current_search_col;
 311 }
 312 
 313 static void
 314 e_tree_state_change (ETree *et)
 315 {
 316 	if (et->priv->state_change_freeze)
 317 		et->priv->state_changed = TRUE;
 318 	else
 319 		g_signal_emit (et, et_signals[STATE_CHANGE], 0);
 320 }
 321 
 322 static void
 323 change_trigger (GObject *object,
 324                 ETree *et)
 325 {
 326 	e_tree_state_change (et);
 327 }
 328 
 329 static void
 330 search_col_change_trigger (GObject *object,
 331                            ETree *et)
 332 {
 333 	clear_current_search_col (et);
 334 	e_tree_state_change (et);
 335 }
 336 
 337 static void
 338 disconnect_header (ETree *e_tree)
 339 {
 340 	if (e_tree->priv->header == NULL)
 341 		return;
 342 
 343 	if (e_tree->priv->structure_change_id)
 344 		g_signal_handler_disconnect (
 345 			e_tree->priv->header,
 346 			e_tree->priv->structure_change_id);
 347 	if (e_tree->priv->expansion_change_id)
 348 		g_signal_handler_disconnect (
 349 			e_tree->priv->header,
 350 			e_tree->priv->expansion_change_id);
 351 	if (e_tree->priv->sort_info) {
 352 		if (e_tree->priv->sort_info_change_id)
 353 			g_signal_handler_disconnect (
 354 				e_tree->priv->sort_info,
 355 				e_tree->priv->sort_info_change_id);
 356 		if (e_tree->priv->group_info_change_id)
 357 			g_signal_handler_disconnect (
 358 				e_tree->priv->sort_info,
 359 				e_tree->priv->group_info_change_id);
 360 
 361 		g_object_unref (e_tree->priv->sort_info);
 362 	}
 363 	g_object_unref (e_tree->priv->header);
 364 	e_tree->priv->header = NULL;
 365 	e_tree->priv->sort_info = NULL;
 366 }
 367 
 368 static void
 369 connect_header (ETree *e_tree,
 370                 ETableState *state)
 371 {
 372 	GValue *val = g_new0 (GValue, 1);
 373 
 374 	if (e_tree->priv->header != NULL)
 375 		disconnect_header (e_tree);
 376 
 377 	e_tree->priv->header = e_table_state_to_header (
 378 		GTK_WIDGET (e_tree), e_tree->priv->full_header, state);
 379 
 380 	e_tree->priv->structure_change_id = g_signal_connect (
 381 		e_tree->priv->header, "structure_change",
 382 		G_CALLBACK (search_col_change_trigger), e_tree);
 383 
 384 	e_tree->priv->expansion_change_id = g_signal_connect (
 385 		e_tree->priv->header, "expansion_change",
 386 		G_CALLBACK (change_trigger), e_tree);
 387 
 388 	if (state->sort_info) {
 389 		e_tree->priv->sort_info = e_table_sort_info_duplicate (state->sort_info);
 390 		e_table_sort_info_set_can_group (e_tree->priv->sort_info, FALSE);
 391 		e_tree->priv->sort_info_change_id = g_signal_connect (
 392 			e_tree->priv->sort_info, "sort_info_changed",
 393 			G_CALLBACK (search_col_change_trigger), e_tree);
 394 
 395 		e_tree->priv->group_info_change_id = g_signal_connect (
 396 			e_tree->priv->sort_info, "group_info_changed",
 397 			G_CALLBACK (search_col_change_trigger), e_tree);
 398 	} else
 399 		e_tree->priv->sort_info = NULL;
 400 
 401 	g_value_init (val, G_TYPE_OBJECT);
 402 	g_value_set_object (val, e_tree->priv->sort_info);
 403 	g_object_set_property (G_OBJECT (e_tree->priv->header), "sort_info", val);
 404 	g_free (val);
 405 }
 406 
 407 static void
 408 et_dispose (GObject *object)
 409 {
 410 	ETreePrivate *priv;
 411 
 412 	priv = E_TREE_GET_PRIVATE (object);
 413 
 414 	if (priv->search != NULL) {
 415 		g_signal_handler_disconnect (
 416 			priv->search, priv->search_search_id);
 417 		g_signal_handler_disconnect (
 418 			priv->search, priv->search_accept_id);
 419 		g_object_unref (priv->search);
 420 		priv->search = NULL;
 421 	}
 422 
 423 	if (priv->reflow_idle_id > 0) {
 424 		g_source_remove (priv->reflow_idle_id);
 425 		priv->reflow_idle_id = 0;
 426 	}
 427 
 428 	scroll_off (E_TREE (object));
 429 	hover_off (E_TREE (object));
 430 	g_list_foreach (
 431 		priv->expanded_list,
 432 		(GFunc) g_free, NULL);
 433 	g_list_free (priv->expanded_list);
 434 	priv->expanded_list = NULL;
 435 
 436 	et_disconnect_from_etta (E_TREE (object));
 437 
 438 	if (priv->etta != NULL) {
 439 		g_object_unref (priv->etta);
 440 		priv->etta = NULL;
 441 	}
 442 
 443 	if (priv->model != NULL) {
 444 		g_object_unref (priv->model);
 445 		priv->model = NULL;
 446 	}
 447 
 448 	if (priv->full_header != NULL) {
 449 		g_object_unref (priv->full_header);
 450 		priv->full_header = NULL;
 451 	}
 452 
 453 	disconnect_header (E_TREE (object));
 454 
 455 	if (priv->selection != NULL) {
 456 		g_object_unref (priv->selection);
 457 		priv->selection = NULL;
 458 	}
 459 
 460 	if (priv->spec != NULL) {
 461 		g_object_unref (priv->spec);
 462 		priv->spec = NULL;
 463 	}
 464 
 465 	if (priv->sorter != NULL) {
 466 		g_object_unref (priv->sorter);
 467 		priv->sorter = NULL;
 468 	}
 469 
 470 	if (priv->header_canvas != NULL) {
 471 		gtk_widget_destroy (GTK_WIDGET (priv->header_canvas));
 472 		priv->header_canvas = NULL;
 473 	}
 474 
 475 	if (priv->site)
 476 		e_tree_drag_source_unset (E_TREE (object));
 477 
 478 	if (priv->last_drop_context != NULL) {
 479 		g_object_weak_unref (
 480 			G_OBJECT (priv->last_drop_context),
 481 			context_destroyed, object);
 482 		priv->last_drop_context = NULL;
 483 	}
 484 
 485 	if (priv->info_text != NULL) {
 486 		g_object_run_dispose (G_OBJECT (priv->info_text));
 487 		priv->info_text = NULL;
 488 	}
 489 	priv->info_text_resize_id = 0;
 490 
 491 	if (priv->table_canvas != NULL) {
 492 		gtk_widget_destroy (GTK_WIDGET (priv->table_canvas));
 493 		priv->table_canvas = NULL;
 494 	}
 495 
 496 	/* do not unref it, it was owned by priv->table_canvas */
 497 	priv->item = NULL;
 498 
 499 	/* Chain up to parent's dispose() method. */
 500 	G_OBJECT_CLASS (e_tree_parent_class)->dispose (object);
 501 }
 502 
 503 static void
 504 et_unrealize (GtkWidget *widget)
 505 {
 506 	scroll_off (E_TREE (widget));
 507 	hover_off (E_TREE (widget));
 508 
 509 	if (GTK_WIDGET_CLASS (e_tree_parent_class)->unrealize)
 510 		GTK_WIDGET_CLASS (e_tree_parent_class)->unrealize (widget);
 511 }
 512 
 513 typedef struct {
 514 	ETree *et;
 515 	gchar *string;
 516 } SearchSearchStruct;
 517 
 518 static gboolean
 519 search_search_callback (ETreeModel *model,
 520                         ETreePath path,
 521                         gpointer data)
 522 {
 523 	SearchSearchStruct *cb_data = data;
 524 	gconstpointer value;
 525 	ETableCol *col = current_search_col (cb_data->et);
 526 
 527 	value = e_tree_model_value_at (
 528 		model, path, cb_data->et->priv->current_search_col->col_idx);
 529 
 530 	return col->search (value, cb_data->string);
 531 }
 532 
 533 static gboolean
 534 et_search_search (ETableSearch *search,
 535                   gchar *string,
 536                   ETableSearchFlags flags,
 537                   ETree *et)
 538 {
 539 	ETreePath cursor;
 540 	ETreePath found;
 541 	SearchSearchStruct cb_data;
 542 	ETableCol *col = current_search_col (et);
 543 
 544 	if (col == NULL)
 545 		return FALSE;
 546 
 547 	cb_data.et = et;
 548 	cb_data.string = string;
 549 
 550 	cursor = e_tree_get_cursor (et);
 551 
 552 	if (cursor && (flags & E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST)) {
 553 		gconstpointer value;
 554 
 555 		value = e_tree_model_value_at (et->priv->model, cursor, col->col_idx);
 556 
 557 		if (col->search (value, string)) {
 558 			return TRUE;
 559 		}
 560 	}
 561 
 562 	found = e_tree_model_node_find (
 563 			et->priv->model, cursor, NULL,
 564 			E_TREE_FIND_NEXT_FORWARD,
 565 			search_search_callback, &cb_data);
 566 	if (found == NULL)
 567 		found = e_tree_model_node_find (
 568 			et->priv->model, NULL, cursor,
 569 			E_TREE_FIND_NEXT_FORWARD,
 570 			search_search_callback, &cb_data);
 571 
 572 	if (found && found != cursor) {
 573 		gint model_row;
 574 
 575 		e_tree_table_adapter_show_node (et->priv->etta, found);
 576 		model_row = e_tree_table_adapter_row_of_node (et->priv->etta, found);
 577 
 578 		e_selection_model_select_as_key_press (
 579 			E_SELECTION_MODEL (et->priv->selection),
 580 			model_row, col->col_idx, GDK_CONTROL_MASK);
 581 		return TRUE;
 582 	} else if (cursor && !(flags & E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST)) {
 583 		gconstpointer value;
 584 
 585 		value = e_tree_model_value_at (et->priv->model, cursor, col->col_idx);
 586 
 587 		return col->search (value, string);
 588 	} else
 589 		return FALSE;
 590 }
 591 
 592 static void
 593 et_search_accept (ETableSearch *search,
 594                   ETree *et)
 595 {
 596 	ETableCol *col = current_search_col (et);
 597 	gint cursor;
 598 
 599 	if (col == NULL)
 600 		return;
 601 
 602 	g_object_get (et->priv->selection, "cursor_row", &cursor, NULL);
 603 
 604 	e_selection_model_select_as_key_press (
 605 		E_SELECTION_MODEL (et->priv->selection),
 606 		cursor, col->col_idx, 0);
 607 }
 608 
 609 static void
 610 e_tree_init (ETree *e_tree)
 611 {
 612 	gtk_widget_set_can_focus (GTK_WIDGET (e_tree), TRUE);
 613 
 614 	gtk_table_set_homogeneous (GTK_TABLE (e_tree), FALSE);
 615 
 616 	e_tree->priv = E_TREE_GET_PRIVATE (e_tree);
 617 
 618 	e_tree->priv->alternating_row_colors = 1;
 619 	e_tree->priv->horizontal_draw_grid = 1;
 620 	e_tree->priv->vertical_draw_grid = 1;
 621 	e_tree->priv->draw_focus = 1;
 622 	e_tree->priv->cursor_mode = E_CURSOR_SIMPLE;
 623 	e_tree->priv->length_threshold = 200;
 624 
 625 	e_tree->priv->drop_row = -1;
 626 	e_tree->priv->drop_col = -1;
 627 
 628 	e_tree->priv->drag_row = -1;
 629 	e_tree->priv->drag_col = -1;
 630 
 631 #ifdef E_TREE_USE_TREE_SELECTION
 632 	e_tree->priv->selection =
 633 		E_SELECTION_MODEL (e_tree_selection_model_new ());
 634 #else
 635 	e_tree->priv->selection =
 636 		E_SELECTION_MODEL (e_table_selection_model_new ());
 637 #endif
 638 
 639 	e_tree->priv->search = e_table_search_new ();
 640 
 641 	e_tree->priv->search_search_id = g_signal_connect (
 642 		e_tree->priv->search, "search",
 643 		G_CALLBACK (et_search_search), e_tree);
 644 
 645 	e_tree->priv->search_accept_id = g_signal_connect (
 646 		e_tree->priv->search, "accept",
 647 		G_CALLBACK (et_search_accept), e_tree);
 648 
 649 	e_tree->priv->always_search = g_getenv ("GAL_ALWAYS_SEARCH") ? TRUE : FALSE;
 650 
 651 	e_tree->priv->state_changed = FALSE;
 652 	e_tree->priv->state_change_freeze = 0;
 653 
 654 	e_tree->priv->is_dragging = FALSE;
 655 }
 656 
 657 /* Grab_focus handler for the ETree */
 658 static void
 659 et_grab_focus (GtkWidget *widget)
 660 {
 661 	ETree *e_tree;
 662 
 663 	e_tree = E_TREE (widget);
 664 
 665 	gtk_widget_grab_focus (GTK_WIDGET (e_tree->priv->table_canvas));
 666 }
 667 
 668 /* Focus handler for the ETree */
 669 static gint
 670 et_focus (GtkWidget *container,
 671           GtkDirectionType direction)
 672 {
 673 	ETree *e_tree;
 674 
 675 	e_tree = E_TREE (container);
 676 
 677 	if (gtk_container_get_focus_child (GTK_CONTAINER (container))) {
 678 		gtk_container_set_focus_child (GTK_CONTAINER (container), NULL);
 679 		return FALSE;
 680 	}
 681 
 682 	return gtk_widget_child_focus (
 683 		GTK_WIDGET (e_tree->priv->table_canvas), direction);
 684 }
 685 
 686 static void
 687 set_header_canvas_width (ETree *e_tree)
 688 {
 689 	gdouble oldwidth, oldheight, width;
 690 
 691 	if (!(e_tree->priv->header_item &&
 692 		e_tree->priv->header_canvas && e_tree->priv->table_canvas))
 693 		return;
 694 
 695 	gnome_canvas_get_scroll_region (
 696 		GNOME_CANVAS (e_tree->priv->table_canvas),
 697 		NULL, NULL, &width, NULL);
 698 	gnome_canvas_get_scroll_region (
 699 		GNOME_CANVAS (e_tree->priv->header_canvas),
 700 		NULL, NULL, &oldwidth, &oldheight);
 701 
 702 	if (oldwidth != width ||
 703 	    oldheight != E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height - 1)
 704 		gnome_canvas_set_scroll_region (
 705 			GNOME_CANVAS (e_tree->priv->header_canvas),
 706 			0, 0, width, /*  COLUMN_HEADER_HEIGHT - 1 */
 707 			E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height - 1);
 708 
 709 }
 710 
 711 static void
 712 header_canvas_size_allocate (GtkWidget *widget,
 713                              GtkAllocation *alloc,
 714                              ETree *e_tree)
 715 {
 716 	GtkAllocation allocation;
 717 
 718 	set_header_canvas_width (e_tree);
 719 
 720 	widget = GTK_WIDGET (e_tree->priv->header_canvas);
 721 	gtk_widget_get_allocation (widget, &allocation);
 722 
 723 	/* When the header item is created ->height == 0,
 724 	 * as the font is only created when everything is realized.
 725 	 * So we set the usize here as well, so that the size of the
 726 	 * header is correct */
 727 	if (allocation.height != E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height)
 728 		gtk_widget_set_size_request (
 729 			widget, -1,
 730 			E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height);
 731 }
 732 
 733 static void
 734 e_tree_setup_header (ETree *e_tree)
 735 {
 736 	GtkWidget *widget;
 737 	gchar *pointer;
 738 
 739 	widget = e_canvas_new ();
 740 	gtk_widget_set_can_focus (widget, FALSE);
 741 	e_tree->priv->header_canvas = GNOME_CANVAS (widget);
 742 	gtk_widget_show (widget);
 743 
 744 	pointer = g_strdup_printf ("%p", (gpointer) e_tree);
 745 
 746 	e_tree->priv->header_item = gnome_canvas_item_new (
 747 		gnome_canvas_root (e_tree->priv->header_canvas),
 748 		e_table_header_item_get_type (),
 749 		"ETableHeader", e_tree->priv->header,
 750 		"full_header", e_tree->priv->full_header,
 751 		"sort_info", e_tree->priv->sort_info,
 752 		"dnd_code", pointer,
 753 		"tree", e_tree,
 754 		NULL);
 755 
 756 	g_free (pointer);
 757 
 758 	g_signal_connect (
 759 		e_tree->priv->header_canvas, "size_allocate",
 760 		G_CALLBACK (header_canvas_size_allocate), e_tree);
 761 
 762 	gtk_widget_set_size_request (
 763 		GTK_WIDGET (e_tree->priv->header_canvas), -1,
 764 		E_TABLE_HEADER_ITEM (e_tree->priv->header_item)->height);
 765 }
 766 
 767 static void
 768 scroll_to_cursor (ETree *e_tree)
 769 {
 770 	ETreePath path;
 771 	GtkAdjustment *adjustment;
 772 	GtkScrollable *scrollable;
 773 	gint x, y, w, h;
 774 	gdouble page_size;
 775 	gdouble lower;
 776 	gdouble upper;
 777 	gdouble value;
 778 
 779 	path = e_tree_get_cursor (e_tree);
 780 	x = y = w = h = 0;
 781 
 782 	if (path) {
 783 		gint row = e_tree_row_of_node (e_tree, path);
 784 		gint col = 0;
 785 
 786 		if (row >= 0)
 787 			e_table_item_get_cell_geometry (
 788 				E_TABLE_ITEM (e_tree->priv->item),
 789 				&row, &col, &x, &y, &w, &h);
 790 	}
 791 
 792 	scrollable = GTK_SCROLLABLE (e_tree->priv->table_canvas);
 793 	adjustment = gtk_scrollable_get_vadjustment (scrollable);
 794 
 795 	page_size = gtk_adjustment_get_page_size (adjustment);
 796 	lower = gtk_adjustment_get_lower (adjustment);
 797 	upper = gtk_adjustment_get_upper (adjustment);
 798 	value = gtk_adjustment_get_value (adjustment);
 799 
 800 	if (y < value || y + h > value + page_size) {
 801 		value = CLAMP (y - page_size / 2, lower, upper - page_size);
 802 		gtk_adjustment_set_value (adjustment, value);
 803 	}
 804 }
 805 
 806 static gboolean
 807 tree_canvas_reflow_idle (ETree *e_tree)
 808 {
 809 	gdouble height, width;
 810 	gdouble oldheight, oldwidth;
 811 	GtkAllocation allocation;
 812 	GtkWidget *widget;
 813 
 814 	widget = GTK_WIDGET (e_tree->priv->table_canvas);
 815 	gtk_widget_get_allocation (widget, &allocation);
 816 
 817 	g_object_get (
 818 		e_tree->priv->item,
 819 		"height", &height, "width", &width, NULL);
 820 
 821 	height = MAX ((gint) height, allocation.height);
 822 	width = MAX ((gint) width, allocation.width);
 823 
 824 	/* I have no idea why this needs to be -1, but it works. */
 825 	gnome_canvas_get_scroll_region (
 826 		GNOME_CANVAS (e_tree->priv->table_canvas),
 827 		NULL, NULL, &oldwidth, &oldheight);
 828 
 829 	if (oldwidth != width - 1 ||
 830 	    oldheight != height - 1) {
 831 		gnome_canvas_set_scroll_region (
 832 			GNOME_CANVAS (e_tree->priv->table_canvas),
 833 			0, 0, width - 1, height - 1);
 834 		set_header_canvas_width (e_tree);
 835 	}
 836 
 837 	e_tree->priv->reflow_idle_id = 0;
 838 
 839 	if (e_tree->priv->show_cursor_after_reflow) {
 840 		e_tree->priv->show_cursor_after_reflow = FALSE;
 841 		scroll_to_cursor (e_tree);
 842 	}
 843 
 844 	return FALSE;
 845 }
 846 
 847 static void
 848 tree_canvas_size_allocate (GtkWidget *widget,
 849                            GtkAllocation *alloc,
 850                            ETree *e_tree)
 851 {
 852 	gdouble width;
 853 	gdouble height;
 854 	GValue *val = g_new0 (GValue, 1);
 855 	g_value_init (val, G_TYPE_DOUBLE);
 856 
 857 	width = alloc->width;
 858 	g_value_set_double (val, width);
 859 	g_object_get (
 860 		e_tree->priv->item,
 861 		"height", &height,
 862 		NULL);
 863 	height = MAX ((gint) height, alloc->height);
 864 
 865 	g_object_set (
 866 		e_tree->priv->item,
 867 		"width", width,
 868 		NULL);
 869 	g_object_set_property (G_OBJECT (e_tree->priv->header), "width", val);
 870 	g_free (val);
 871 
 872 	if (e_tree->priv->reflow_idle_id)
 873 		g_source_remove (e_tree->priv->reflow_idle_id);
 874 	tree_canvas_reflow_idle (e_tree);
 875 }
 876 
 877 static void
 878 tree_canvas_reflow (GnomeCanvas *canvas,
 879                     ETree *e_tree)
 880 {
 881 	if (!e_tree->priv->reflow_idle_id)
 882 		e_tree->priv->reflow_idle_id = g_idle_add_full (
 883 			400, (GSourceFunc) tree_canvas_reflow_idle,
 884 			e_tree, NULL);
 885 }
 886 
 887 static void
 888 item_cursor_change (ETableItem *eti,
 889                     gint row,
 890                     ETree *et)
 891 {
 892 	ETreePath path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
 893 
 894 	g_signal_emit (et, et_signals[CURSOR_CHANGE], 0, row, path);
 895 }
 896 
 897 static void
 898 item_cursor_activated (ETableItem *eti,
 899                        gint row,
 900                        ETree *et)
 901 {
 902 	ETreePath path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
 903 
 904 	g_signal_emit (et, et_signals[CURSOR_ACTIVATED], 0, row, path);
 905 }
 906 
 907 static void
 908 item_double_click (ETableItem *eti,
 909                    gint row,
 910                    gint col,
 911                    GdkEvent *event,
 912                    ETree *et)
 913 {
 914 	ETreePath path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
 915 
 916 	g_signal_emit (et, et_signals[DOUBLE_CLICK], 0, row, path, col, event);
 917 }
 918 
 919 static gboolean
 920 item_right_click (ETableItem *eti,
 921                   gint row,
 922                   gint col,
 923                   GdkEvent *event,
 924                   ETree *et)
 925 {
 926 	ETreePath path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
 927 	gboolean return_val = 0;
 928 
 929 	g_signal_emit (
 930 		et, et_signals[RIGHT_CLICK], 0,
 931 		row, path, col, event, &return_val);
 932 
 933 	return return_val;
 934 }
 935 
 936 static gboolean
 937 item_click (ETableItem *eti,
 938             gint row,
 939             gint col,
 940             GdkEvent *event,
 941             ETree *et)
 942 {
 943 	gboolean return_val = 0;
 944 	ETreePath path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
 945 
 946 	g_signal_emit (
 947 		et, et_signals[CLICK], 0, row, path, col, event, &return_val);
 948 
 949 	return return_val;
 950 }
 951 
 952 static gint
 953 item_key_press (ETableItem *eti,
 954                 gint row,
 955                 gint col,
 956                 GdkEvent *event,
 957                 ETree *et)
 958 {
 959 	gint return_val = 0;
 960 	GdkEventKey *key = (GdkEventKey *) event;
 961 	ETreePath path;
 962 	gint y, row_local, col_local;
 963 	GtkAdjustment *adjustment;
 964 	GtkScrollable *scrollable;
 965 	gdouble page_size;
 966 	gdouble upper;
 967 	gdouble value;
 968 
 969 	scrollable = GTK_SCROLLABLE (et->priv->table_canvas);
 970 	adjustment = gtk_scrollable_get_vadjustment (scrollable);
 971 
 972 	page_size = gtk_adjustment_get_page_size (adjustment);
 973 	upper = gtk_adjustment_get_upper (adjustment);
 974 	value = gtk_adjustment_get_value (adjustment);
 975 
 976 	switch (key->keyval) {
 977 	case GDK_KEY_Page_Down:
 978 	case GDK_KEY_KP_Page_Down:
 979 		y = CLAMP (value + (2 * page_size - 50), 0, upper);
 980 		y -= value;
 981 		e_tree_get_cell_at (et, 30, y, &row_local, &col_local);
 982 
 983 		if (row_local == -1)
The left operand of '==' is a garbage value
(emitted by clang-analyzer)

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

The left operand of '==' is a garbage value
(emitted by clang-analyzer)

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

984 row_local = e_table_model_row_count ( 985 E_TABLE_MODEL (et->priv->etta)) - 1; 986 987 row_local = e_tree_view_to_model_row (et, row_local); 988 col_local = e_selection_model_cursor_col ( 989 E_SELECTION_MODEL (et->priv->selection)); 990 e_selection_model_select_as_key_press ( 991 E_SELECTION_MODEL (et->priv->selection), 992 row_local, col_local, key->state); 993 994 return_val = 1; 995 break; 996 case GDK_KEY_Page_Up: 997 case GDK_KEY_KP_Page_Up: 998 y = CLAMP (value - (page_size - 50), 0, upper); 999 y -= value; 1000 e_tree_get_cell_at (et, 30, y, &row_local, &col_local); 1001 1002 if (row_local == -1)
The left operand of '==' is a garbage value
(emitted by clang-analyzer)

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

The left operand of '==' is a garbage value
(emitted by clang-analyzer)

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

1003 row_local = e_table_model_row_count ( 1004 E_TABLE_MODEL (et->priv->etta)) - 1; 1005 1006 row_local = e_tree_view_to_model_row (et, row_local); 1007 col_local = e_selection_model_cursor_col ( 1008 E_SELECTION_MODEL (et->priv->selection)); 1009 e_selection_model_select_as_key_press ( 1010 E_SELECTION_MODEL (et->priv->selection), 1011 row_local, col_local, key->state); 1012 1013 return_val = 1; 1014 break; 1015 case GDK_KEY_plus: 1016 case GDK_KEY_KP_Add: 1017 case GDK_KEY_Right: 1018 case GDK_KEY_KP_Right: 1019 /* Only allow if the Shift modifier is used. 1020 * eg. Ctrl-Equal shouldn't be handled. */ 1021 if ((key->state & (GDK_SHIFT_MASK | GDK_LOCK_MASK | 1022 GDK_MOD1_MASK)) != GDK_SHIFT_MASK) 1023 break; 1024 if (row != -1) { 1025 path = e_tree_table_adapter_node_at_row ( 1026 et->priv->etta, row); 1027 if (path) 1028 e_tree_table_adapter_node_set_expanded ( 1029 et->priv->etta, path, TRUE); 1030 } 1031 return_val = 1; 1032 break; 1033 case GDK_KEY_underscore: 1034 case GDK_KEY_KP_Subtract: 1035 case GDK_KEY_Left: 1036 case GDK_KEY_KP_Left: 1037 /* Only allow if the Shift modifier is used. 1038 * eg. Ctrl-Minus shouldn't be handled. */ 1039 if ((key->state & (GDK_SHIFT_MASK | GDK_LOCK_MASK | 1040 GDK_MOD1_MASK)) != GDK_SHIFT_MASK) 1041 break; 1042 if (row != -1) { 1043 path = e_tree_table_adapter_node_at_row ( 1044 et->priv->etta, row); 1045 if (path) 1046 e_tree_table_adapter_node_set_expanded ( 1047 et->priv->etta, path, FALSE); 1048 } 1049 return_val = 1; 1050 break; 1051 case GDK_KEY_BackSpace: 1052 if (e_table_search_backspace (et->priv->search)) 1053 return TRUE; 1054 /* Fallthrough */ 1055 default: 1056 if ((key->state & ~(GDK_SHIFT_MASK | GDK_LOCK_MASK | 1057 GDK_MOD1_MASK | GDK_MOD2_MASK | GDK_MOD3_MASK | 1058 GDK_MOD4_MASK | GDK_MOD5_MASK)) == 0 1059 && ((key->keyval >= GDK_KEY_a && key->keyval <= GDK_KEY_z) || 1060 (key->keyval >= GDK_KEY_A && key->keyval <= GDK_KEY_Z) || 1061 (key->keyval >= GDK_KEY_0 && key->keyval <= GDK_KEY_9))) { 1062 e_table_search_input_character (et->priv->search, key->keyval); 1063 } 1064 path = e_tree_table_adapter_node_at_row (et->priv->etta, row); 1065 g_signal_emit ( 1066 et, 1067 et_signals[KEY_PRESS], 0, 1068 row, path, col, event, &return_val); 1069 break; 1070 } 1071 return return_val; 1072 } 1073 1074 static gint 1075 item_start_drag (ETableItem *eti, 1076 gint row, 1077 gint col, 1078 GdkEvent *event, 1079 ETree *et) 1080 { 1081 ETreePath path; 1082 gint return_val = 0; 1083 1084 path = e_tree_table_adapter_node_at_row (et->priv->etta, row); 1085 1086 g_signal_emit ( 1087 et, et_signals[START_DRAG], 0, 1088 row, path, col, event, &return_val); 1089 1090 return return_val; 1091 } 1092 1093 static void 1094 et_selection_model_selection_changed (ETableSelectionModel *etsm, 1095 ETree *et) 1096 { 1097 g_signal_emit (et, et_signals[SELECTION_CHANGE], 0); 1098 } 1099 1100 static void 1101 et_selection_model_selection_row_changed (ETableSelectionModel *etsm, 1102 gint row, 1103 ETree *et) 1104 { 1105 g_signal_emit (et, et_signals[SELECTION_CHANGE], 0); 1106 } 1107 1108 static void 1109 et_build_item (ETree *et) 1110 { 1111 et->priv->item = gnome_canvas_item_new ( 1112 GNOME_CANVAS_GROUP ( 1113 gnome_canvas_root (et->priv->table_canvas)), 1114 e_table_item_get_type (), 1115 "ETableHeader", et->priv->header, 1116 "ETableModel", et->priv->etta, 1117 "selection_model", et->priv->selection, 1118 "alternating_row_colors", et->priv->alternating_row_colors, 1119 "horizontal_draw_grid", et->priv->horizontal_draw_grid, 1120 "vertical_draw_grid", et->priv->vertical_draw_grid, 1121 "drawfocus", et->priv->draw_focus, 1122 "cursor_mode", et->priv->cursor_mode, 1123 "length_threshold", et->priv->length_threshold, 1124 "uniform_row_height", et->priv->uniform_row_height, 1125 NULL); 1126 1127 g_signal_connect ( 1128 et->priv->item, "cursor_change", 1129 G_CALLBACK (item_cursor_change), et); 1130 g_signal_connect ( 1131 et->priv->item, "cursor_activated", 1132 G_CALLBACK (item_cursor_activated), et); 1133 g_signal_connect ( 1134 et->priv->item, "double_click", 1135 G_CALLBACK (item_double_click), et); 1136 g_signal_connect ( 1137 et->priv->item, "right_click", 1138 G_CALLBACK (item_right_click), et); 1139 g_signal_connect ( 1140 et->priv->item, "click", 1141 G_CALLBACK (item_click), et); 1142 g_signal_connect ( 1143 et->priv->item, "key_press", 1144 G_CALLBACK (item_key_press), et); 1145 g_signal_connect ( 1146 et->priv->item, "start_drag", 1147 G_CALLBACK (item_start_drag), et); 1148 } 1149 1150 static void 1151 et_canvas_style_set (GtkWidget *widget, 1152 GtkStyle *prev_style) 1153 { 1154 GtkStyle *style; 1155 1156 style = gtk_widget_get_style (widget); 1157 1158 gnome_canvas_item_set ( 1159 E_TREE (widget)->priv->white_item, 1160 "fill_color_gdk", &style->base[GTK_STATE_NORMAL], 1161 NULL); 1162 } 1163 1164 static gboolean 1165 white_item_event (GnomeCanvasItem *white_item, 1166 GdkEvent *event, 1167 ETree *e_tree) 1168 { 1169 gboolean return_val = 0; 1170 g_signal_emit ( 1171 e_tree, 1172 et_signals[WHITE_SPACE_EVENT], 0, 1173 event, &return_val); 1174 return return_val; 1175 } 1176 1177 static gint 1178 et_canvas_root_event (GnomeCanvasItem *root, 1179 GdkEvent *event, 1180 ETree *e_tree) 1181 { 1182 switch (event->type) { 1183 case GDK_BUTTON_PRESS: 1184 case GDK_2BUTTON_PRESS: 1185 case GDK_BUTTON_RELEASE: 1186 if (event->button.button != 4 && event->button.button != 5) { 1187 if (gtk_widget_has_focus (GTK_WIDGET (root->canvas))) { 1188 GnomeCanvasItem *item = GNOME_CANVAS (root->canvas)->focused_item; 1189 1190 if (E_IS_TABLE_ITEM (item)) { 1191 e_table_item_leave_edit (E_TABLE_ITEM (item)); 1192 return TRUE; 1193 } 1194 } 1195 } 1196 break; 1197 default: 1198 break; 1199 } 1200 1201 return FALSE; 1202 } 1203 1204 /* Handler for focus events in the table_canvas; we have to repaint ourselves 1205 * and give the focus to some ETableItem. 1206 */ 1207 static gboolean 1208 table_canvas_focus_event_cb (GtkWidget *widget, 1209 GdkEventFocus *event, 1210 gpointer data) 1211 { 1212 GnomeCanvas *canvas; 1213 ETree *tree; 1214 1215 gtk_widget_queue_draw (widget); 1216 1217 if (!event->in) 1218 return TRUE; 1219 1220 canvas = GNOME_CANVAS (widget); 1221 tree = E_TREE (data); 1222 1223 if (!canvas->focused_item || 1224 (e_selection_model_cursor_row (tree->priv->selection) == -1)) { 1225 e_table_item_set_cursor (E_TABLE_ITEM (tree->priv->item), 0, 0); 1226 gnome_canvas_item_grab_focus (tree->priv->item); 1227 } 1228 1229 return TRUE; 1230 } 1231 1232 static void 1233 e_tree_setup_table (ETree *e_tree) 1234 { 1235 GtkWidget *widget; 1236 GtkStyle *style; 1237 1238 e_tree->priv->table_canvas = GNOME_CANVAS (e_canvas_new ()); 1239 g_signal_connect ( 1240 e_tree->priv->table_canvas, "size_allocate", 1241 G_CALLBACK (tree_canvas_size_allocate), e_tree); 1242 g_signal_connect ( 1243 e_tree->priv->table_canvas, "focus_in_event", 1244 G_CALLBACK (table_canvas_focus_event_cb), e_tree); 1245 g_signal_connect ( 1246 e_tree->priv->table_canvas, "focus_out_event", 1247 G_CALLBACK (table_canvas_focus_event_cb), e_tree); 1248 1249 g_signal_connect ( 1250 e_tree->priv->table_canvas, "drag_begin", 1251 G_CALLBACK (et_drag_begin), e_tree); 1252 g_signal_connect ( 1253 e_tree->priv->table_canvas, "drag_end", 1254 G_CALLBACK (et_drag_end), e_tree); 1255 g_signal_connect ( 1256 e_tree->priv->table_canvas, "drag_data_get", 1257 G_CALLBACK (et_drag_data_get), e_tree); 1258 g_signal_connect ( 1259 e_tree->priv->table_canvas, "drag_data_delete", 1260 G_CALLBACK (et_drag_data_delete), e_tree); 1261 g_signal_connect ( 1262 e_tree, "drag_motion", 1263 G_CALLBACK (et_drag_motion), e_tree); 1264 g_signal_connect ( 1265 e_tree, "drag_leave", 1266 G_CALLBACK (et_drag_leave), e_tree); 1267 g_signal_connect ( 1268 e_tree, "drag_drop", 1269 G_CALLBACK (et_drag_drop), e_tree); 1270 g_signal_connect ( 1271 e_tree, "drag_data_received", 1272 G_CALLBACK (et_drag_data_received), e_tree); 1273 1274 g_signal_connect ( 1275 e_tree->priv->table_canvas, "reflow", 1276 G_CALLBACK (tree_canvas_reflow), e_tree); 1277 1278 widget = GTK_WIDGET (e_tree->priv->table_canvas); 1279 style = gtk_widget_get_style (widget); 1280 1281 gtk_widget_show (widget); 1282 1283 e_tree->priv->white_item = gnome_canvas_item_new ( 1284 gnome_canvas_root (e_tree->priv->table_canvas), 1285 e_canvas_background_get_type (), 1286 "fill_color_gdk", &style->base[GTK_STATE_NORMAL], 1287 NULL); 1288 1289 g_signal_connect ( 1290 e_tree->priv->white_item, "event", 1291 G_CALLBACK (white_item_event), e_tree); 1292 g_signal_connect ( 1293 gnome_canvas_root (e_tree->priv->table_canvas), "event", 1294 G_CALLBACK (et_canvas_root_event), e_tree); 1295 1296 et_build_item (e_tree); 1297 } 1298 1299 /** 1300 * e_tree_set_search_column: 1301 * @e_tree: #ETree object that will be modified 1302 * @col: Column index to use for searches 1303 * 1304 * This routine sets the current search column to be used for keypress 1305 * searches of the #ETree. If -1 is passed in for column, the current 1306 * search column is cleared. 1307 */ 1308 void 1309 e_tree_set_search_column (ETree *e_tree, 1310 gint col) 1311 { 1312 if (col == -1) { 1313 clear_current_search_col (e_tree); 1314 return; 1315 } 1316 1317 e_tree->priv->search_col_set = TRUE; 1318 e_tree->priv->current_search_col = e_table_header_get_column ( 1319 e_tree->priv->full_header, col); 1320 } 1321 1322 void 1323 e_tree_set_state_object (ETree *e_tree, 1324 ETableState *state) 1325 { 1326 GValue *val; 1327 GtkAllocation allocation; 1328 GtkWidget *widget; 1329 1330 val = g_new0 (GValue, 1); 1331 g_value_init (val, G_TYPE_DOUBLE); 1332 1333 connect_header (e_tree, state); 1334 1335 widget = GTK_WIDGET (e_tree->priv->table_canvas); 1336 gtk_widget_get_allocation (widget, &allocation); 1337 1338 g_value_set_double (val, (gdouble) allocation.width); 1339 g_object_set_property (G_OBJECT (e_tree->priv->header), "width", val); 1340 g_free (val); 1341 1342 if (e_tree->priv->header_item) 1343 g_object_set ( 1344 e_tree->priv->header_item, 1345 "ETableHeader", e_tree->priv->header, 1346 "sort_info", e_tree->priv->sort_info, 1347 NULL); 1348 1349 if (e_tree->priv->item) 1350 g_object_set ( 1351 e_tree->priv->item, 1352 "ETableHeader", e_tree->priv->header, 1353 NULL); 1354 1355 if (e_tree->priv->etta) 1356 e_tree_table_adapter_set_sort_info ( 1357 e_tree->priv->etta, e_tree->priv->sort_info); 1358 1359 e_tree_state_change (e_tree); 1360 } 1361 1362 /** 1363 * e_tree_set_state: 1364 * @e_tree: #ETree object that will be modified 1365 * @state_str: a string with the XML representation of the #ETableState. 1366 * 1367 * This routine sets the state (as described by #ETableState) of the 1368 * #ETree object. 1369 */ 1370 void 1371 e_tree_set_state (ETree *e_tree, 1372 const gchar *state_str) 1373 { 1374 ETableState *state; 1375 1376 g_return_if_fail (e_tree != NULL); 1377 g_return_if_fail (E_IS_TREE (e_tree)); 1378 g_return_if_fail (state_str != NULL); 1379 1380 state = e_table_state_new (); 1381 e_table_state_load_from_string (state, state_str); 1382 1383 if (state->col_count > 0) 1384 e_tree_set_state_object (e_tree, state); 1385 1386 g_object_unref (state); 1387 } 1388 1389 /** 1390 * e_tree_load_state: 1391 * @e_tree: #ETree object that will be modified 1392 * @filename: name of the file containing the state to be loaded into the #ETree 1393 * 1394 * An #ETableState will be loaded form the file pointed by @filename into the 1395 * @e_tree object. 1396 */ 1397 void 1398 e_tree_load_state (ETree *e_tree, 1399 const gchar *filename) 1400 { 1401 ETableState *state; 1402 1403 g_return_if_fail (e_tree != NULL); 1404 g_return_if_fail (E_IS_TREE (e_tree)); 1405 g_return_if_fail (filename != NULL); 1406 1407 state = e_table_state_new (); 1408 e_table_state_load_from_file (state, filename); 1409 1410 if (state->col_count > 0) 1411 e_tree_set_state_object (e_tree, state); 1412 1413 g_object_unref (state); 1414 } 1415 1416 /** 1417 * e_tree_get_state_object: 1418 * @e_tree: #ETree object to act on 1419 * 1420 * Builds an #ETableState corresponding to the current state of the 1421 * #ETree. 1422 * 1423 * Return value: 1424 * The %ETableState object generated. 1425 **/ 1426 ETableState * 1427 e_tree_get_state_object (ETree *e_tree) 1428 { 1429 ETableState *state; 1430 gint full_col_count; 1431 gint i, j; 1432 1433 state = e_table_state_new (); 1434 state->sort_info = e_tree->priv->sort_info; 1435 if (state->sort_info) 1436 g_object_ref (state->sort_info); 1437 1438 state->col_count = e_table_header_count (e_tree->priv->header); 1439 full_col_count = e_table_header_count (e_tree->priv->full_header); 1440 state->columns = g_new (int, state->col_count); 1441 state->expansions = g_new (double, state->col_count); 1442 for (i = 0; i < state->col_count; i++) { 1443 ETableCol *col = e_table_header_get_column (e_tree->priv->header, i); 1444 state->columns[i] = -1; 1445 for (j = 0; j < full_col_count; j++) { 1446 if (col->col_idx == e_table_header_index (e_tree->priv->full_header, j)) { 1447 state->columns[i] = j; 1448 break; 1449 } 1450 } 1451 state->expansions[i] = col->expansion; 1452 } 1453 1454 return state; 1455 } 1456 1457 /** 1458 * e_tree_get_state: 1459 * @e_tree: The #ETree to act on 1460 * 1461 * Builds a state object based on the current state and returns the 1462 * string corresponding to that state. 1463 * 1464 * Return value: 1465 * A string describing the current state of the #ETree. 1466 **/ 1467 gchar * 1468 e_tree_get_state (ETree *e_tree) 1469 { 1470 ETableState *state; 1471 gchar *string; 1472 1473 state = e_tree_get_state_object (e_tree); 1474 string = e_table_state_save_to_string (state); 1475 g_object_unref (state); 1476 return string; 1477 } 1478 1479 /** 1480 * e_tree_save_state: 1481 * @e_tree: The #ETree to act on 1482 * @filename: name of the file to save to 1483 * 1484 * Saves the state of the @e_tree object into the file pointed by 1485 * @filename. 1486 **/ 1487 void 1488 e_tree_save_state (ETree *e_tree, 1489 const gchar *filename) 1490 { 1491 ETableState *state; 1492 1493 state = e_tree_get_state_object (e_tree); 1494 e_table_state_save_to_file (state, filename); 1495 g_object_unref (state); 1496 } 1497 1498 /** 1499 * e_tree_get_spec: 1500 * @e_tree: The #ETree to query 1501 * 1502 * Returns the specification object. 1503 * 1504 * Return value: 1505 **/ 1506 ETableSpecification * 1507 e_tree_get_spec (ETree *e_tree) 1508 { 1509 return e_tree->priv->spec; 1510 } 1511 1512 static void 1513 et_table_model_changed (ETableModel *model, 1514 ETree *et) 1515 { 1516 if (et->priv->horizontal_scrolling) 1517 e_table_header_update_horizontal (et->priv->header); 1518 } 1519 1520 static void 1521 et_table_row_changed (ETableModel *table_model, 1522 gint row, 1523 ETree *et) 1524 { 1525 et_table_model_changed (table_model, et); 1526 } 1527 1528 static void 1529 et_table_cell_changed (ETableModel *table_model, 1530 gint view_col, 1531 gint row, 1532 ETree *et) 1533 { 1534 et_table_model_changed (table_model, et); 1535 } 1536 1537 static void 1538 et_table_rows_deleted (ETableModel *table_model, 1539 gint row, 1540 gint count, 1541 ETree *et) 1542 { 1543 ETreePath * node, * prev_node; 1544 1545 /* If the cursor is still valid after this deletion, we're done */ 1546 if (e_selection_model_cursor_row (et->priv->selection) >= 0 1547 || row == 0) 1548 return; 1549 1550 prev_node = e_tree_node_at_row (et, row - 1); 1551 node = e_tree_get_cursor (et); 1552 1553 /* Check if the cursor is a child of the node directly before the 1554 * deleted region (implying that an expander was collapsed with 1555 * the cursor inside it) */ 1556 while (node) { 1557 node = e_tree_model_node_get_parent (et->priv->model, node); 1558 if (node == prev_node) { 1559 /* Set the cursor to the still-visible parent */ 1560 e_tree_set_cursor (et, prev_node); 1561 return; 1562 } 1563 } 1564 } 1565 1566 static void 1567 et_connect_to_etta (ETree *et) 1568 { 1569 et->priv->table_model_change_id = g_signal_connect ( 1570 et->priv->etta, "model_changed", 1571 G_CALLBACK (et_table_model_changed), et); 1572 1573 et->priv->table_row_change_id = g_signal_connect ( 1574 et->priv->etta, "model_row_changed", 1575 G_CALLBACK (et_table_row_changed), et); 1576 1577 et->priv->table_cell_change_id = g_signal_connect ( 1578 et->priv->etta, "model_cell_changed", 1579 G_CALLBACK (et_table_cell_changed), et); 1580 1581 et->priv->table_rows_delete_id = g_signal_connect ( 1582 et->priv->etta, "model_rows_deleted", 1583 G_CALLBACK (et_table_rows_deleted), et); 1584 1585 } 1586 1587 static gboolean 1588 et_real_construct (ETree *e_tree, 1589 ETreeModel *etm, 1590 ETableExtras *ete, 1591 ETableSpecification *specification, 1592 ETableState *state) 1593 { 1594 GtkAdjustment *adjustment; 1595 GtkScrollable *scrollable; 1596 gint row = 0; 1597 1598 if (ete) 1599 g_object_ref (ete); 1600 else 1601 ete = e_table_extras_new (); 1602 1603 e_tree->priv->alternating_row_colors = specification->alternating_row_colors; 1604 e_tree->priv->horizontal_draw_grid = specification->horizontal_draw_grid; 1605 e_tree->priv->vertical_draw_grid = specification->vertical_draw_grid; 1606 e_tree->priv->draw_focus = specification->draw_focus; 1607 e_tree->priv->cursor_mode = specification->cursor_mode; 1608 e_tree->priv->full_header = e_table_spec_to_full_header (specification, ete); 1609 1610 connect_header (e_tree, state); 1611 1612 e_tree->priv->horizontal_scrolling = specification->horizontal_scrolling; 1613 1614 e_tree->priv->model = etm; 1615 g_object_ref (etm); 1616 1617 e_tree->priv->etta = E_TREE_TABLE_ADAPTER ( 1618 e_tree_table_adapter_new (e_tree->priv->model, 1619 e_tree->priv->sort_info, e_tree->priv->full_header)); 1620 1621 et_connect_to_etta (e_tree); 1622 1623 e_tree->priv->sorter = e_sorter_new (); 1624 1625 g_object_set ( 1626 e_tree->priv->selection, 1627 "sorter", e_tree->priv->sorter, 1628 #ifdef E_TREE_USE_TREE_SELECTION 1629 "model", e_tree->priv->model, 1630 "etta", e_tree->priv->etta, 1631 #else 1632 "model", e_tree->priv->etta, 1633 #endif 1634 "selection_mode", specification->selection_mode, 1635 "cursor_mode", specification->cursor_mode, 1636 NULL); 1637 1638 g_signal_connect ( 1639 e_tree->priv->selection, "selection_changed", 1640 G_CALLBACK (et_selection_model_selection_changed), e_tree); 1641 g_signal_connect ( 1642 e_tree->priv->selection, "selection_row_changed", 1643 G_CALLBACK (et_selection_model_selection_row_changed), e_tree); 1644 1645 if (!specification->no_headers) { 1646 e_tree_setup_header (e_tree); 1647 } 1648 e_tree_setup_table (e_tree); 1649 1650 scrollable = GTK_SCROLLABLE (e_tree->priv->table_canvas); 1651 1652 adjustment = gtk_scrollable_get_vadjustment (scrollable); 1653 gtk_adjustment_set_step_increment (adjustment, 20); 1654 1655 adjustment = gtk_scrollable_get_hadjustment (scrollable); 1656 gtk_adjustment_set_step_increment (adjustment, 20); 1657 1658 if (!specification->no_headers) { 1659 /* 1660 * The header 1661 */ 1662 gtk_table_attach ( 1663 GTK_TABLE (e_tree), 1664 GTK_WIDGET (e_tree->priv->header_canvas), 1665 0, 1, 0 + row, 1 + row, 1666 GTK_FILL | GTK_EXPAND, 1667 GTK_FILL, 0, 0); 1668 row++; 1669 } 1670 1671 gtk_table_attach ( 1672 GTK_TABLE (e_tree), 1673 GTK_WIDGET (e_tree->priv->table_canvas), 1674 0, 1, 0 + row, 1 + row, 1675 GTK_FILL | GTK_EXPAND, 1676 GTK_FILL | GTK_EXPAND, 1677 0, 0); 1678 1679 g_object_unref (ete); 1680 1681 return e_tree != NULL; 1682 } 1683 1684 /** 1685 * e_tree_construct: 1686 * @e_tree: The newly created #ETree object. 1687 * @etm: The model for this table. 1688 * @ete: An optional #ETableExtras. (%NULL is valid.) 1689 * @spec_str: The spec. 1690 * @state_str: An optional state. (%NULL is valid.) 1691 * 1692 * This is the internal implementation of e_tree_new() for use by 1693 * subclasses or language bindings. See e_tree_new() for details. 1694 * 1695 * Return value: %TRUE on success, %FALSE if an error occurred 1696 **/ 1697 gboolean 1698 e_tree_construct (ETree *e_tree, 1699 ETreeModel *etm, 1700 ETableExtras *ete, 1701 const gchar *spec_str, 1702 const gchar *state_str) 1703 { 1704 ETableSpecification *specification; 1705 ETableState *state; 1706 1707 g_return_val_if_fail (e_tree != NULL, FALSE); 1708 g_return_val_if_fail (E_IS_TREE (e_tree), FALSE); 1709 g_return_val_if_fail (etm != NULL, FALSE); 1710 g_return_val_if_fail (E_IS_TREE_MODEL (etm), FALSE); 1711 g_return_val_if_fail (ete == NULL || E_IS_TABLE_EXTRAS (ete), FALSE); 1712 g_return_val_if_fail (spec_str != NULL, FALSE); 1713 1714 specification = e_table_specification_new (); 1715 if (!e_table_specification_load_from_string (specification, spec_str)) { 1716 g_object_unref (specification); 1717 return FALSE; 1718 } 1719 if (state_str) { 1720 state = e_table_state_new (); 1721 e_table_state_load_from_string (state, state_str); 1722 if (state->col_count <= 0) { 1723 g_object_unref (state); 1724 state = specification->state; 1725 g_object_ref (state); 1726 } 1727 } else { 1728 state = specification->state; 1729 g_object_ref (state); 1730 } 1731 1732 if (!et_real_construct (e_tree, etm, ete, specification, state)) { 1733 g_object_unref (specification); 1734 g_object_unref (state); 1735 return FALSE; 1736 } 1737 1738 e_tree->priv->spec = specification; 1739 e_tree->priv->spec->allow_grouping = FALSE; 1740 1741 g_object_unref (state); 1742 1743 return TRUE; 1744 } 1745 1746 /** 1747 * e_tree_construct_from_spec_file: 1748 * @e_tree: The newly created #ETree object. 1749 * @etm: The model for this tree 1750 * @ete: An optional #ETableExtras (%NULL is valid.) 1751 * @spec_fn: The filename of the spec 1752 * @state_fn: An optional state file (%NULL is valid.) 1753 * 1754 * This is the internal implementation of e_tree_new_from_spec_file() 1755 * for use by subclasses or language bindings. See 1756 * e_tree_new_from_spec_file() for details. 1757 * 1758 * Return value: %TRUE on success, %FALSE if an error occurred 1759 **/ 1760 gboolean 1761 e_tree_construct_from_spec_file (ETree *e_tree, 1762 ETreeModel *etm, 1763 ETableExtras *ete, 1764 const gchar *spec_fn, 1765 const gchar *state_fn) 1766 { 1767 ETableSpecification *specification; 1768 ETableState *state; 1769 1770 g_return_val_if_fail (e_tree != NULL, FALSE); 1771 g_return_val_if_fail (E_IS_TREE (e_tree), FALSE); 1772 g_return_val_if_fail (etm != NULL, FALSE); 1773 g_return_val_if_fail (E_IS_TREE_MODEL (etm), FALSE); 1774 g_return_val_if_fail (ete == NULL || E_IS_TABLE_EXTRAS (ete), FALSE); 1775 g_return_val_if_fail (spec_fn != NULL, FALSE); 1776 1777 specification = e_table_specification_new (); 1778 if (!e_table_specification_load_from_file (specification, spec_fn)) { 1779 g_object_unref (specification); 1780 return FALSE; 1781 } 1782 if (state_fn) { 1783 state = e_table_state_new (); 1784 if (!e_table_state_load_from_file (state, state_fn)) { 1785 g_object_unref (state); 1786 state = specification->state; 1787 g_object_ref (state); 1788 } 1789 if (state->col_count <= 0) { 1790 g_object_unref (state); 1791 state = specification->state; 1792 g_object_ref (state); 1793 } 1794 } else { 1795 state = specification->state; 1796 g_object_ref (state); 1797 } 1798 1799 if (!et_real_construct (e_tree, etm, ete, specification, state)) { 1800 g_object_unref (specification); 1801 g_object_unref (state); 1802 return FALSE; 1803 } 1804 1805 e_tree->priv->spec = specification; 1806 e_tree->priv->spec->allow_grouping = FALSE; 1807 1808 g_object_unref (state); 1809 1810 return TRUE; 1811 } 1812 1813 /** 1814 * e_tree_new: 1815 * @etm: The model for this tree 1816 * @ete: An optional #ETableExtras (%NULL is valid.) 1817 * @spec: The spec 1818 * @state: An optional state (%NULL is valid.) 1819 * 1820 * This function creates an #ETree from the given parameters. The 1821 * #ETreeModel is a tree model to be represented. The #ETableExtras 1822 * is an optional set of pixbufs, cells, and sorting functions to be 1823 * used when interpreting the spec. If you pass in %NULL it uses the 1824 * default #ETableExtras. (See e_table_extras_new()). 1825 * 1826 * @spec is the specification of the set of viewable columns and the 1827 * default sorting state and such. @state is an optional string 1828 * specifying the current sorting state and such. If @state is NULL, 1829 * then the default state from the spec will be used. 1830 * 1831 * Return value: 1832 * The newly created #ETree or %NULL if there's an error. 1833 **/ 1834 GtkWidget * 1835 e_tree_new (ETreeModel *etm, 1836 ETableExtras *ete, 1837 const gchar *spec, 1838 const gchar *state) 1839 { 1840 ETree *e_tree; 1841 1842 g_return_val_if_fail (etm != NULL, NULL); 1843 g_return_val_if_fail (E_IS_TREE_MODEL (etm), NULL); 1844 g_return_val_if_fail (ete == NULL || E_IS_TABLE_EXTRAS (ete), NULL); 1845 g_return_val_if_fail (spec != NULL, NULL); 1846 1847 e_tree = g_object_new (E_TYPE_TREE, NULL); 1848 1849 if (!e_tree_construct (e_tree, etm, ete, spec, state)) { 1850 g_object_unref (e_tree); 1851 return NULL; 1852 } 1853 1854 return (GtkWidget *) e_tree; 1855 } 1856 1857 /** 1858 * e_tree_new_from_spec_file: 1859 * @etm: The model for this tree. 1860 * @ete: An optional #ETableExtras. (%NULL is valid.) 1861 * @spec_fn: The filename of the spec. 1862 * @state_fn: An optional state file. (%NULL is valid.) 1863 * 1864 * This is very similar to e_tree_new(), except instead of passing in 1865 * strings you pass in the file names of the spec and state to load. 1866 * 1867 * @spec_fn is the filename of the spec to load. If this file doesn't 1868 * exist, e_tree_new_from_spec_file will return %NULL. 1869 * 1870 * @state_fn is the filename of the initial state to load. If this is 1871 * %NULL or if the specified file doesn't exist, the default state 1872 * from the spec file is used. 1873 * 1874 * Return value: 1875 * The newly created #ETree or %NULL if there's an error. 1876 **/ 1877 GtkWidget * 1878 e_tree_new_from_spec_file (ETreeModel *etm, 1879 ETableExtras *ete, 1880 const gchar *spec_fn, 1881 const gchar *state_fn) 1882 { 1883 ETree *e_tree; 1884 1885 g_return_val_if_fail (etm != NULL, NULL); 1886 g_return_val_if_fail (E_IS_TREE_MODEL (etm), NULL); 1887 g_return_val_if_fail (ete == NULL || E_IS_TABLE_EXTRAS (ete), NULL); 1888 g_return_val_if_fail (spec_fn != NULL, NULL); 1889 1890 e_tree = g_object_new (E_TYPE_TREE, NULL); 1891 1892 if (!e_tree_construct_from_spec_file (e_tree, etm, ete, spec_fn, state_fn)) { 1893 g_object_unref (e_tree); 1894 return NULL; 1895 } 1896 1897 return (GtkWidget *) e_tree; 1898 } 1899 1900 void 1901 e_tree_show_cursor_after_reflow (ETree *e_tree) 1902 { 1903 g_return_if_fail (e_tree != NULL); 1904 g_return_if_fail (E_IS_TREE (e_tree)); 1905 1906 e_tree->priv->show_cursor_after_reflow = TRUE; 1907 } 1908 1909 void 1910 e_tree_set_cursor (ETree *e_tree, 1911 ETreePath path) 1912 { 1913 #ifndef E_TREE_USE_TREE_SELECTION 1914 gint row; 1915 #endif 1916 g_return_if_fail (e_tree != NULL); 1917 g_return_if_fail (E_IS_TREE (e_tree)); 1918 g_return_if_fail (path != NULL); 1919 1920 #ifdef E_TREE_USE_TREE_SELECTION 1921 e_tree_selection_model_select_single_path ( 1922 E_TREE_SELECTION_MODEL (e_tree->priv->selection), path); 1923 e_tree_selection_model_change_cursor ( 1924 E_TREE_SELECTION_MODEL (e_tree->priv->selection), path); 1925 #else 1926 row = e_tree_table_adapter_row_of_node ( 1927 E_TREE_TABLE_ADAPTER (e_tree->priv->etta), path); 1928 1929 if (row == -1) 1930 return; 1931 1932 g_object_set ( 1933 e_tree->priv->selection, 1934 "cursor_row", row, 1935 NULL); 1936 #endif 1937 } 1938 1939 ETreePath 1940 e_tree_get_cursor (ETree *e_tree) 1941 { 1942 #ifdef E_TREE_USE_TREE_SELECTION 1943 return e_tree_selection_model_get_cursor ( 1944 E_TREE_SELECTION_MODEL (e_tree->priv->selection)); 1945 #else 1946 gint row; 1947 g_return_val_if_fail (e_tree != NULL, NULL); 1948 g_return_val_if_fail (E_IS_TREE (e_tree), NULL); 1949 1950 g_object_get ( 1951 e_tree->priv->selection, 1952 "cursor_row", &row, 1953 NULL); 1954 if (row == -1) 1955 return NULL; 1956 1957 return e_tree_table_adapter_node_at_row ( 1958 E_TREE_TABLE_ADAPTER (e_tree->priv->etta), row); 1959 #endif 1960 } 1961 1962 void 1963 e_tree_selected_row_foreach (ETree *e_tree, 1964 EForeachFunc callback, 1965 gpointer closure) 1966 { 1967 g_return_if_fail (e_tree != NULL); 1968 g_return_if_fail (E_IS_TREE (e_tree)); 1969 1970 e_selection_model_foreach (e_tree->priv->selection, 1971 callback, 1972 closure); 1973 } 1974 1975 #ifdef E_TREE_USE_TREE_SELECTION 1976 void 1977 e_tree_selected_path_foreach (ETree *e_tree, 1978 ETreeForeachFunc callback, 1979 gpointer closure) 1980 { 1981 g_return_if_fail (e_tree != NULL); 1982 g_return_if_fail (E_IS_TREE (e_tree)); 1983 1984 e_tree_selection_model_foreach ( 1985 E_TREE_SELECTION_MODEL (e_tree->priv->selection), 1986 callback, closure); 1987 } 1988 1989 /* Standard functions */ 1990 static void 1991 et_foreach_recurse (ETreeModel *model, 1992 ETreePath path, 1993 ETreeForeachFunc callback, 1994 gpointer closure) 1995 { 1996 ETreePath child; 1997 1998 callback (path, closure); 1999 2000 child = e_tree_model_node_get_first_child (E_TREE_MODEL (model), path); 2001 for (; child; child = e_tree_model_node_get_next (E_TREE_MODEL (model), child)) 2002 if (child) 2003 et_foreach_recurse (model, child, callback, closure); 2004 } 2005 2006 void 2007 e_tree_path_foreach (ETree *e_tree, 2008 ETreeForeachFunc callback, 2009 gpointer closure) 2010 { 2011 ETreePath root; 2012 2013 g_return_if_fail (e_tree != NULL); 2014 g_return_if_fail (E_IS_TREE (e_tree)); 2015 2016 root = e_tree_model_get_root (e_tree->priv->model); 2017 2018 if (root) 2019 et_foreach_recurse (e_tree->priv->model, 2020 root, 2021 callback, 2022 closure); 2023 } 2024 #endif 2025 2026 EPrintable * 2027 e_tree_get_printable (ETree *e_tree) 2028 { 2029 g_return_val_if_fail (e_tree != NULL, NULL); 2030 g_return_val_if_fail (E_IS_TREE (e_tree), NULL); 2031 2032 return e_table_item_get_printable (E_TABLE_ITEM (e_tree->priv->item)); 2033 } 2034 2035 static void 2036 et_get_property (GObject *object, 2037 guint property_id, 2038 GValue *value, 2039 GParamSpec *pspec) 2040 { 2041 ETree *etree = E_TREE (object); 2042 2043 switch (property_id) { 2044 case PROP_ETTA: 2045 g_value_set_object (value, etree->priv->etta); 2046 break; 2047 2048 case PROP_UNIFORM_ROW_HEIGHT: 2049 g_value_set_boolean (value, etree->priv->uniform_row_height); 2050 break; 2051 2052 case PROP_ALWAYS_SEARCH: 2053 g_value_set_boolean (value, etree->priv->always_search); 2054 break; 2055 2056 case PROP_HADJUSTMENT: 2057 if (etree->priv->table_canvas) 2058 g_object_get_property ( 2059 G_OBJECT (etree->priv->table_canvas), 2060 "hadjustment", value); 2061 else 2062 g_value_set_object (value, NULL); 2063 break; 2064 2065 case PROP_VADJUSTMENT: 2066 if (etree->priv->table_canvas) 2067 g_object_get_property ( 2068 G_OBJECT (etree->priv->table_canvas), 2069 "vadjustment", value); 2070 else 2071 g_value_set_object (value, NULL); 2072 break; 2073 2074 case PROP_HSCROLL_POLICY: 2075 if (etree->priv->table_canvas) 2076 g_object_get_property ( 2077 G_OBJECT (etree->priv->table_canvas), 2078 "hscroll-policy", value); 2079 else 2080 g_value_set_enum (value, 0); 2081 break; 2082 2083 case PROP_VSCROLL_POLICY: 2084 if (etree->priv->table_canvas) 2085 g_object_get_property ( 2086 G_OBJECT (etree->priv->table_canvas), 2087 "vscroll-policy", value); 2088 else 2089 g_value_set_enum (value, 0); 2090 break; 2091 2092 default: 2093 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 2094 break; 2095 } 2096 } 2097 2098 typedef struct { 2099 gchar *arg; 2100 gboolean setting; 2101 } bool_closure; 2102 2103 static void 2104 et_set_property (GObject *object, 2105 guint property_id, 2106 const GValue *value, 2107 GParamSpec *pspec) 2108 { 2109 ETree *etree = E_TREE (object); 2110 2111 switch (property_id) { 2112 case PROP_LENGTH_THRESHOLD: 2113 etree->priv->length_threshold = g_value_get_int (value); 2114 if (etree->priv->item) { 2115 gnome_canvas_item_set ( 2116 GNOME_CANVAS_ITEM (etree->priv->item), 2117 "length_threshold", 2118 etree->priv->length_threshold, 2119 NULL); 2120 } 2121 break; 2122 2123 case PROP_HORIZONTAL_DRAW_GRID: 2124 etree->priv->horizontal_draw_grid = g_value_get_boolean (value); 2125 if (etree->priv->item) { 2126 gnome_canvas_item_set ( 2127 GNOME_CANVAS_ITEM (etree->priv->item), 2128 "horizontal_draw_grid", 2129 etree->priv->horizontal_draw_grid, 2130 NULL); 2131 } 2132 break; 2133 2134 case PROP_VERTICAL_DRAW_GRID: 2135 etree->priv->vertical_draw_grid = g_value_get_boolean (value); 2136 if (etree->priv->item) { 2137 gnome_canvas_item_set ( 2138 GNOME_CANVAS_ITEM (etree->priv->item), 2139 "vertical_draw_grid", 2140 etree->priv->vertical_draw_grid, 2141 NULL); 2142 } 2143 break; 2144 2145 case PROP_DRAW_FOCUS: 2146 etree->priv->draw_focus = g_value_get_boolean (value); 2147 if (etree->priv->item) { 2148 gnome_canvas_item_set ( 2149 GNOME_CANVAS_ITEM (etree->priv->item), 2150 "drawfocus", 2151 etree->priv->draw_focus, 2152 NULL); 2153 } 2154 break; 2155 2156 case PROP_UNIFORM_ROW_HEIGHT: 2157 etree->priv->uniform_row_height = g_value_get_boolean (value); 2158 if (etree->priv->item) { 2159 gnome_canvas_item_set ( 2160 GNOME_CANVAS_ITEM (etree->priv->item), 2161 "uniform_row_height", 2162 etree->priv->uniform_row_height, 2163 NULL); 2164 } 2165 break; 2166 2167 case PROP_ALWAYS_SEARCH: 2168 if (etree->priv->always_search == g_value_get_boolean (value)) 2169 return; 2170 etree->priv->always_search = g_value_get_boolean (value); 2171 clear_current_search_col (etree); 2172 break; 2173 2174 case PROP_HADJUSTMENT: 2175 if (etree->priv->table_canvas) 2176 g_object_set_property ( 2177 G_OBJECT (etree->priv->table_canvas), 2178 "hadjustment", value); 2179 break; 2180 2181 case PROP_VADJUSTMENT: 2182 if (etree->priv->table_canvas) 2183 g_object_set_property ( 2184 G_OBJECT (etree->priv->table_canvas), 2185 "vadjustment", value); 2186 break; 2187 2188 case PROP_HSCROLL_POLICY: 2189 if (etree->priv->table_canvas) 2190 g_object_set_property ( 2191 G_OBJECT (etree->priv->table_canvas), 2192 "hscroll-policy", value); 2193 break; 2194 2195 case PROP_VSCROLL_POLICY: 2196 if (etree->priv->table_canvas) 2197 g_object_set_property ( 2198 G_OBJECT (etree->priv->table_canvas), 2199 "vscroll-policy", value); 2200 break; 2201 } 2202 } 2203 2204 gint 2205 e_tree_get_next_row (ETree *e_tree, 2206 gint model_row) 2207 { 2208 g_return_val_if_fail (e_tree != NULL, -1); 2209 g_return_val_if_fail (E_IS_TREE (e_tree), -1); 2210 2211 if (e_tree->priv->sorter) { 2212 gint i; 2213 i = e_sorter_model_to_sorted (E_SORTER (e_tree->priv->sorter), model_row); 2214 i++; 2215 if (i < e_table_model_row_count (E_TABLE_MODEL (e_tree->priv->etta))) { 2216 return e_sorter_sorted_to_model (E_SORTER (e_tree->priv->sorter), i); 2217 } else 2218 return -1; 2219 } else { 2220 gint row_count; 2221 2222 row_count = e_table_model_row_count ( 2223 E_TABLE_MODEL (e_tree->priv->etta)); 2224 2225 if (model_row < row_count - 1) 2226 return model_row + 1; 2227 else 2228 return -1; 2229 } 2230 } 2231 2232 gint 2233 e_tree_get_prev_row (ETree *e_tree, 2234 gint model_row) 2235 { 2236 g_return_val_if_fail (e_tree != NULL, -1); 2237 g_return_val_if_fail (E_IS_TREE (e_tree), -1); 2238 2239 if (e_tree->priv->sorter) { 2240 gint i; 2241 i = e_sorter_model_to_sorted (E_SORTER (e_tree->priv->sorter), model_row); 2242 i--; 2243 if (i >= 0) 2244 return e_sorter_sorted_to_model (E_SORTER (e_tree->priv->sorter), i); 2245 else 2246 return -1; 2247 } else 2248 return model_row - 1; 2249 } 2250 2251 gint 2252 e_tree_model_to_view_row (ETree *e_tree, 2253 gint model_row) 2254 { 2255 g_return_val_if_fail (e_tree != NULL, -1); 2256 g_return_val_if_fail (E_IS_TREE (e_tree), -1); 2257 2258 if (e_tree->priv->sorter) 2259 return e_sorter_model_to_sorted (E_SORTER (e_tree->priv->sorter), model_row); 2260 else 2261 return model_row; 2262 } 2263 2264 gint 2265 e_tree_view_to_model_row (ETree *e_tree, 2266 gint view_row) 2267 { 2268 g_return_val_if_fail (e_tree != NULL, -1); 2269 g_return_val_if_fail (E_IS_TREE (e_tree), -1); 2270 2271 if (e_tree->priv->sorter) 2272 return e_sorter_sorted_to_model (E_SORTER (e_tree->priv->sorter), view_row); 2273 else 2274 return view_row; 2275 } 2276 2277 gboolean 2278 e_tree_node_is_expanded (ETree *et, 2279 ETreePath path) 2280 { 2281 g_return_val_if_fail (path, FALSE); 2282 2283 return e_tree_table_adapter_node_is_expanded (et->priv->etta, path); 2284 } 2285 2286 void 2287 e_tree_node_set_expanded (ETree *et, 2288 ETreePath path, 2289 gboolean expanded) 2290 { 2291 g_return_if_fail (et != NULL); 2292 g_return_if_fail (E_IS_TREE (et)); 2293 2294 e_tree_table_adapter_node_set_expanded (et->priv->etta, path, expanded); 2295 } 2296 2297 void 2298 e_tree_node_set_expanded_recurse (ETree *et, 2299 ETreePath path, 2300 gboolean expanded) 2301 { 2302 g_return_if_fail (et != NULL); 2303 g_return_if_fail (E_IS_TREE (et)); 2304 2305 e_tree_table_adapter_node_set_expanded_recurse (et->priv->etta, path, expanded); 2306 } 2307 2308 void 2309 e_tree_root_node_set_visible (ETree *et, 2310 gboolean visible) 2311 { 2312 g_return_if_fail (et != NULL); 2313 g_return_if_fail (E_IS_TREE (et)); 2314 2315 e_tree_table_adapter_root_node_set_visible (et->priv->etta, visible); 2316 } 2317 2318 ETreePath 2319 e_tree_node_at_row (ETree *et, 2320 gint row) 2321 { 2322 ETreePath path; 2323 2324 path = e_tree_table_adapter_node_at_row (et->priv->etta, row); 2325 2326 return path; 2327 } 2328 2329 gint 2330 e_tree_row_of_node (ETree *et, 2331 ETreePath path) 2332 { 2333 return e_tree_table_adapter_row_of_node (et->priv->etta, path); 2334 } 2335 2336 gboolean 2337 e_tree_root_node_is_visible (ETree *et) 2338 { 2339 return e_tree_table_adapter_root_node_is_visible (et->priv->etta); 2340 } 2341 2342 void 2343 e_tree_show_node (ETree *et, 2344 ETreePath path) 2345 { 2346 g_return_if_fail (et != NULL); 2347 g_return_if_fail (E_IS_TREE (et)); 2348 2349 e_tree_table_adapter_show_node (et->priv->etta, path); 2350 } 2351 2352 void 2353 e_tree_save_expanded_state (ETree *et, 2354 gchar *filename) 2355 { 2356 g_return_if_fail (et != NULL); 2357 g_return_if_fail (E_IS_TREE (et)); 2358 2359 e_tree_table_adapter_save_expanded_state (et->priv->etta, filename); 2360 } 2361 2362 void 2363 e_tree_load_expanded_state (ETree *et, 2364 gchar *filename) 2365 { 2366 e_tree_table_adapter_load_expanded_state (et->priv->etta, filename); 2367 } 2368 2369 xmlDoc * 2370 e_tree_save_expanded_state_xml (ETree *et) 2371 { 2372 g_return_val_if_fail (et != NULL, NULL); 2373 g_return_val_if_fail (E_IS_TREE (et), NULL); 2374 2375 return e_tree_table_adapter_save_expanded_state_xml (et->priv->etta); 2376 } 2377 2378 void 2379 e_tree_load_expanded_state_xml (ETree *et, 2380 xmlDoc *doc) 2381 { 2382 g_return_if_fail (et != NULL); 2383 g_return_if_fail (E_IS_TREE (et)); 2384 g_return_if_fail (doc != NULL); 2385 2386 e_tree_table_adapter_load_expanded_state_xml (et->priv->etta, doc); 2387 } 2388 2389 /* state: <0 ... collapse; 0 ... no force - use default; >0 ... expand; 2390 * when using this, be sure to reset to 0 once no forcing is required 2391 * anymore, aka the build of the tree is done */ 2392 void 2393 e_tree_force_expanded_state (ETree *et, 2394 gint state) 2395 { 2396 e_tree_table_adapter_force_expanded_state (et->priv->etta, state); 2397 } 2398 2399 gint 2400 e_tree_row_count (ETree *et) 2401 { 2402 return e_table_model_row_count (E_TABLE_MODEL (et->priv->etta)); 2403 } 2404 2405 GtkWidget * 2406 e_tree_get_tooltip (ETree *et) 2407 { 2408 return E_CANVAS (et->priv->table_canvas)->tooltip_window; 2409 } 2410 2411 static ETreePath 2412 find_next_in_range (ETree *et, 2413 gint start, 2414 gint end, 2415 ETreePathFunc func, 2416 gpointer data) 2417 { 2418 ETreePath path; 2419 gint row; 2420 2421 for (row = start; row <= end; row++) { 2422 path = e_tree_table_adapter_node_at_row (et->priv->etta, row); 2423 if (path && func (et->priv->model, path, data)) 2424 return path; 2425 } 2426 2427 return NULL; 2428 } 2429 2430 static ETreePath 2431 find_prev_in_range (ETree *et, 2432 gint start, 2433 gint end, 2434 ETreePathFunc func, 2435 gpointer data) 2436 { 2437 ETreePath path; 2438 gint row; 2439 2440 for (row = start; row >= end; row--) { 2441 path = e_tree_table_adapter_node_at_row (et->priv->etta, row); 2442 if (path && func (et->priv->model, path, data)) 2443 return path; 2444 } 2445 2446 return NULL; 2447 } 2448 2449 gboolean 2450 e_tree_find_next (ETree *et, 2451 ETreeFindNextParams params, 2452 ETreePathFunc func, 2453 gpointer data) 2454 { 2455 ETreePath cursor, found; 2456 gint row, row_count; 2457 2458 cursor = e_tree_get_cursor (et); 2459 row = e_tree_table_adapter_row_of_node (et->priv->etta, cursor); 2460 row_count = e_table_model_row_count (E_TABLE_MODEL (et->priv->etta)); 2461 2462 if (params & E_TREE_FIND_NEXT_FORWARD) 2463 found = find_next_in_range (et, row + 1, row_count - 1, func, data); 2464 else 2465 found = find_prev_in_range (et, row == -1 ? -1 : row - 1, 0, func, data); 2466 2467 if (found) { 2468 e_tree_table_adapter_show_node (et->priv->etta, found); 2469 e_tree_set_cursor (et, found); 2470 return TRUE; 2471 } 2472 2473 if (params & E_TREE_FIND_NEXT_WRAP) { 2474 if (params & E_TREE_FIND_NEXT_FORWARD) 2475 found = find_next_in_range (et, 0, row, func, data); 2476 else 2477 found = find_prev_in_range (et, row_count - 1, row, func, data); 2478 2479 if (found && found != cursor) { 2480 e_tree_table_adapter_show_node (et->priv->etta, found); 2481 e_tree_set_cursor (et, found); 2482 return TRUE; 2483 } 2484 } 2485 2486 return FALSE; 2487 } 2488 2489 void 2490 e_tree_right_click_up (ETree *et) 2491 { 2492 e_selection_model_right_click_up (et->priv->selection); 2493 } 2494 2495 /** 2496 * e_tree_get_model: 2497 * @et: the ETree 2498 * 2499 * Returns the model upon which this ETree is based. 2500 * 2501 * Returns: the model 2502 **/ 2503 ETreeModel * 2504 e_tree_get_model (ETree *et) 2505 { 2506 g_return_val_if_fail (et != NULL, NULL); 2507 g_return_val_if_fail (E_IS_TREE (et), NULL); 2508 2509 return et->priv->model; 2510 } 2511 2512 /** 2513 * e_tree_get_selection_model: 2514 * @et: the ETree 2515 * 2516 * Returns the selection model of this ETree. 2517 * 2518 * Returns: the selection model 2519 **/ 2520 ESelectionModel * 2521 e_tree_get_selection_model (ETree *et) 2522 { 2523 g_return_val_if_fail (et != NULL, NULL); 2524 g_return_val_if_fail (E_IS_TREE (et), NULL); 2525 2526 return et->priv->selection; 2527 } 2528 2529 /** 2530 * e_tree_get_table_adapter: 2531 * @et: the ETree 2532 * 2533 * Returns the table adapter this ETree uses. 2534 * 2535 * Returns: the model 2536 **/ 2537 ETreeTableAdapter * 2538 e_tree_get_table_adapter (ETree *et) 2539 { 2540 g_return_val_if_fail (et != NULL, NULL); 2541 g_return_val_if_fail (E_IS_TREE (et), NULL); 2542 2543 return et->priv->etta; 2544 } 2545 2546 ETableItem * 2547 e_tree_get_item (ETree *et) 2548 { 2549 g_return_val_if_fail (et != NULL, NULL); 2550 g_return_val_if_fail (E_IS_TREE (et), NULL); 2551 2552 return E_TABLE_ITEM (et->priv->item); 2553 } 2554 2555 GnomeCanvasItem * 2556 e_tree_get_header_item (ETree *et) 2557 { 2558 g_return_val_if_fail (et != NULL, NULL); 2559 g_return_val_if_fail (E_IS_TREE (et), NULL); 2560 2561 return et->priv->header_item; 2562 } 2563 2564 struct _ETreeDragSourceSite 2565 { 2566 GdkModifierType start_button_mask; 2567 GtkTargetList *target_list; /* Targets for drag data */ 2568 GdkDragAction actions; /* Possible actions */ 2569 GdkPixbuf *pixbuf; /* Icon for drag data */ 2570 2571 /* Stored button press information to detect drag beginning */ 2572 gint state; 2573 gint x, y; 2574 gint row, col; 2575 }; 2576 2577 typedef enum 2578 { 2579 GTK_DRAG_STATUS_DRAG, 2580 GTK_DRAG_STATUS_WAIT, 2581 GTK_DRAG_STATUS_DROP 2582 } GtkDragStatus; 2583 2584 typedef struct _GtkDragDestInfo GtkDragDestInfo; 2585 typedef struct _GtkDragSourceInfo GtkDragSourceInfo; 2586 2587 struct _GtkDragDestInfo 2588 { 2589 GtkWidget *widget; /* Widget in which drag is in */ 2590 GdkDragContext *context; /* Drag context */ 2591 GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */ 2592 GtkSelectionData *proxy_data; /* Set while retrieving proxied data */ 2593 guint dropped : 1; /* Set after we receive a drop */ 2594 guint32 proxy_drop_time; /* Timestamp for proxied drop */ 2595 guint proxy_drop_wait : 1; /* Set if we are waiting for a 2596 * status reply before sending 2597 * a proxied drop on. 2598 */ 2599 gint drop_x, drop_y; /* Position of drop */ 2600 }; 2601 2602 struct _GtkDragSourceInfo 2603 { 2604 GtkWidget *widget; 2605 GtkTargetList *target_list; /* Targets for drag data */ 2606 GdkDragAction possible_actions; /* Actions allowed by source */ 2607 GdkDragContext *context; /* drag context */ 2608 GtkWidget *icon_window; /* Window for drag */ 2609 GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */ 2610 GdkCursor *cursor; /* Cursor for drag */ 2611 gint hot_x, hot_y; /* Hot spot for drag */ 2612 gint button; /* mouse button starting drag */ 2613 2614 GtkDragStatus status; /* drag status */ 2615 GdkEvent *last_event; /* motion event waiting for response */ 2616 2617 gint start_x, start_y; /* Initial position */ 2618 gint cur_x, cur_y; /* Current Position */ 2619 2620 GList *selections; /* selections we've claimed */ 2621 2622 GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */ 2623 2624 guint drop_timeout; /* Timeout for aborting drop */ 2625 guint destroy_icon : 1; /* If true, destroy icon_window 2626 */ 2627 }; 2628 2629 /* Drag & drop stuff. */ 2630 /* Target */ 2631 2632 void 2633 e_tree_drag_get_data (ETree *tree, 2634 gint row, 2635 gint col, 2636 GdkDragContext *context, 2637 GdkAtom target, 2638 guint32 time) 2639 { 2640 g_return_if_fail (tree != NULL); 2641 g_return_if_fail (E_IS_TREE (tree)); 2642 2643 gtk_drag_get_data ( 2644 GTK_WIDGET (tree), 2645 context, 2646 target, 2647 time); 2648 2649 } 2650 2651 /** 2652 * e_tree_drag_highlight: 2653 * @tree: 2654 * @row: 2655 * @col: 2656 * 2657 * Set col to -1 to highlight the entire row. 2658 * Set row to -1 to turn off the highlight. 2659 */ 2660 void 2661 e_tree_drag_highlight (ETree *tree, 2662 gint row, 2663 gint col) 2664 { 2665 GtkAllocation allocation; 2666 GtkAdjustment *adjustment; 2667 GtkScrollable *scrollable; 2668 GtkStyle *style; 2669 2670 g_return_if_fail (E_IS_TREE (tree)); 2671 2672 scrollable = GTK_SCROLLABLE (tree->priv->table_canvas); 2673 style = gtk_widget_get_style (GTK_WIDGET (tree)); 2674 gtk_widget_get_allocation (GTK_WIDGET (scrollable), &allocation); 2675 2676 if (row != -1) { 2677 gint x, y, width, height; 2678 if (col == -1) { 2679 e_tree_get_cell_geometry (tree, row, 0, &x, &y, &width, &height); 2680 x = 0; 2681 width = allocation.width; 2682 } else { 2683 e_tree_get_cell_geometry (tree, row, col, &x, &y, &width, &height); 2684 adjustment = gtk_scrollable_get_hadjustment (scrollable); 2685 x += gtk_adjustment_get_value (adjustment);
The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
(emitted by clang-analyzer)

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

The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
(emitted by clang-analyzer)

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

2686 } 2687 2688 adjustment = gtk_scrollable_get_vadjustment (scrollable); 2689 y += gtk_adjustment_get_value (adjustment);
The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
(emitted by clang-analyzer)

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

The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
(emitted by clang-analyzer)

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

2690 2691 if (tree->priv->drop_highlight == NULL) { 2692 tree->priv->drop_highlight = gnome_canvas_item_new ( 2693 gnome_canvas_root (tree->priv->table_canvas), 2694 gnome_canvas_rect_get_type (), 2695 "fill_color", NULL, 2696 "outline_color_gdk", &style->fg[GTK_STATE_NORMAL], 2697 NULL); 2698 } 2699 2700 gnome_canvas_item_set ( 2701 tree->priv->drop_highlight, 2702 "x1", (gdouble) x, 2703 "x2", (gdouble) x + width - 1, 2704 "y1", (gdouble) y, 2705 "y2", (gdouble) y + height - 1, 2706 NULL); 2707 } else { 2708 g_object_run_dispose (G_OBJECT (tree->priv->drop_highlight)); 2709 tree->priv->drop_highlight = NULL; 2710 } 2711 } 2712 2713 void 2714 e_tree_drag_unhighlight (ETree *tree) 2715 { 2716 g_return_if_fail (tree != NULL); 2717 g_return_if_fail (E_IS_TREE (tree)); 2718 2719 if (tree->priv->drop_highlight) { 2720 g_object_run_dispose (G_OBJECT (tree->priv->drop_highlight)); 2721 tree->priv->drop_highlight = NULL; 2722 } 2723 } 2724 2725 void e_tree_drag_dest_set (ETree *tree, 2726 GtkDestDefaults flags, 2727 const GtkTargetEntry *targets, 2728 gint n_targets, 2729 GdkDragAction actions) 2730 { 2731 g_return_if_fail (tree != NULL); 2732 g_return_if_fail (E_IS_TREE (tree)); 2733 2734 gtk_drag_dest_set ( 2735 GTK_WIDGET (tree), 2736 flags, 2737 targets, 2738 n_targets, 2739 actions); 2740 } 2741 2742 void e_tree_drag_dest_set_proxy (ETree *tree, 2743 GdkWindow *proxy_window, 2744 GdkDragProtocol protocol, 2745 gboolean use_coordinates) 2746 { 2747 g_return_if_fail (tree != NULL); 2748 g_return_if_fail (E_IS_TREE (tree)); 2749 2750 gtk_drag_dest_set_proxy ( 2751 GTK_WIDGET (tree), 2752 proxy_window, 2753 protocol, 2754 use_coordinates); 2755 } 2756 2757 /* 2758 * There probably should be functions for setting the targets 2759 * as a GtkTargetList 2760 */ 2761 2762 void 2763 e_tree_drag_dest_unset (GtkWidget *widget) 2764 { 2765 g_return_if_fail (widget != NULL); 2766 g_return_if_fail (E_IS_TREE (widget)); 2767 2768 gtk_drag_dest_unset (widget); 2769 } 2770 2771 /* Source side */ 2772 2773 static gint 2774 et_real_start_drag (ETree *tree, 2775 gint row, 2776 ETreePath path, 2777 gint col, 2778 GdkEvent *event) 2779 { 2780 GtkDragSourceInfo *info; 2781 GdkDragContext *context; 2782 ETreeDragSourceSite *site; 2783 2784 if (tree->priv->do_drag) { 2785 site = tree->priv->site; 2786 2787 site->state = 0; 2788 context = e_tree_drag_begin ( 2789 tree, row, col, 2790 site->target_list, 2791 site->actions, 2792 1, event); 2793 2794 if (context) { 2795 info = g_dataset_get_data (context, "gtk-info"); 2796 2797 if (info && !info->icon_window) { 2798 if (site->pixbuf) 2799 gtk_drag_set_icon_pixbuf ( 2800 context, 2801 site->pixbuf, 2802 -2, -2); 2803 else 2804 gtk_drag_set_icon_default (context); 2805 } 2806 } 2807 return TRUE; 2808 } 2809 return FALSE; 2810 } 2811 2812 void 2813 e_tree_drag_source_set (ETree *tree, 2814 GdkModifierType start_button_mask, 2815 const GtkTargetEntry *targets, 2816 gint n_targets, 2817 GdkDragAction actions) 2818 { 2819 ETreeDragSourceSite *site; 2820 GtkWidget *canvas; 2821 2822 g_return_if_fail (tree != NULL); 2823 g_return_if_fail (E_IS_TREE (tree)); 2824 2825 canvas = GTK_WIDGET (tree->priv->table_canvas); 2826 site = tree->priv->site; 2827 2828 tree->priv->do_drag = TRUE; 2829 2830 gtk_widget_add_events ( 2831 canvas, 2832 gtk_widget_get_events (canvas) | 2833 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | 2834 GDK_BUTTON_MOTION_MASK | GDK_STRUCTURE_MASK); 2835 2836 if (site) { 2837 if (site->target_list) 2838 gtk_target_list_unref (site->target_list); 2839 } else { 2840 site = g_new0 (ETreeDragSourceSite, 1); 2841 tree->priv->site = site; 2842 } 2843 2844 site->start_button_mask = start_button_mask; 2845 2846 if (targets) 2847 site->target_list = gtk_target_list_new (targets, n_targets); 2848 else 2849 site->target_list = NULL; 2850 2851 site->actions = actions; 2852 } 2853 2854 void 2855 e_tree_drag_source_unset (ETree *tree) 2856 { 2857 ETreeDragSourceSite *site; 2858 2859 g_return_if_fail (tree != NULL); 2860 g_return_if_fail (E_IS_TREE (tree)); 2861 2862 site = tree->priv->site; 2863 2864 if (site) { 2865 if (site->target_list) 2866 gtk_target_list_unref (site->target_list); 2867 g_free (site); 2868 tree->priv->site = NULL; 2869 } 2870 } 2871 2872 /* There probably should be functions for setting the targets 2873 * as a GtkTargetList 2874 */ 2875 2876 GdkDragContext * 2877 e_tree_drag_begin (ETree *tree, 2878 gint row, 2879 gint col, 2880 GtkTargetList *targets, 2881 GdkDragAction actions, 2882 gint button, 2883 GdkEvent *event) 2884 { 2885 ETreePath path; 2886 g_return_val_if_fail (tree != NULL, NULL); 2887 g_return_val_if_fail (E_IS_TREE (tree), NULL); 2888 2889 path = e_tree_table_adapter_node_at_row (tree->priv->etta, row); 2890 2891 tree->priv->drag_row = row; 2892 tree->priv->drag_path = path; 2893 tree->priv->drag_col = col; 2894 2895 return gtk_drag_begin ( 2896 GTK_WIDGET (tree->priv->table_canvas), 2897 targets, 2898 actions, 2899 button, 2900 event); 2901 } 2902 2903 /** 2904 * e_tree_is_dragging: 2905 * @tree: An #ETree widget 2906 * 2907 * Returns whether is @tree in a drag&drop operation. 2908 **/ 2909 gboolean 2910 e_tree_is_dragging (ETree *tree) 2911 { 2912 g_return_val_if_fail (tree != NULL, FALSE); 2913 g_return_val_if_fail (tree->priv != NULL, FALSE); 2914 2915 return tree->priv->is_dragging; 2916 } 2917 2918 /** 2919 * e_tree_get_cell_at: 2920 * @tree: An ETree widget 2921 * @x: X coordinate for the pixel 2922 * @y: Y coordinate for the pixel 2923 * @row_return: Pointer to return the row value 2924 * @col_return: Pointer to return the column value 2925 * 2926 * Return the row and column for the cell in which the pixel at (@x, @y) is 2927 * contained. 2928 **/ 2929 void 2930 e_tree_get_cell_at (ETree *tree, 2931 gint x, 2932 gint y, 2933 gint *row_return, 2934 gint *col_return) 2935 { 2936 GtkAdjustment *adjustment; 2937 GtkScrollable *scrollable; 2938 2939 g_return_if_fail (E_IS_TREE (tree)); 2940 g_return_if_fail (row_return != NULL); 2941 g_return_if_fail (col_return != NULL); 2942 2943 /* FIXME it would be nice if it could handle a NULL row_return or 2944 * col_return gracefully. */ 2945 2946 if (row_return) 2947 *row_return = -1; 2948 if (col_return) 2949 *col_return = -1; 2950 2951 scrollable = GTK_SCROLLABLE (tree->priv->table_canvas); 2952 2953 adjustment = gtk_scrollable_get_hadjustment (scrollable); 2954 x += gtk_adjustment_get_value (adjustment); 2955 2956 adjustment = gtk_scrollable_get_vadjustment (scrollable); 2957 y += gtk_adjustment_get_value (adjustment); 2958 2959 e_table_item_compute_location ( 2960 E_TABLE_ITEM (tree->priv->item), 2961 &x, &y, row_return, col_return); 2962 } 2963 2964 /** 2965 * e_tree_get_cell_geometry: 2966 * @tree: The tree. 2967 * @row: The row to get the geometry of. 2968 * @col: The col to get the geometry of. 2969 * @x_return: Returns the x coordinate of the upper right hand corner 2970 * of the cell with respect to the widget. 2971 * @y_return: Returns the y coordinate of the upper right hand corner 2972 * of the cell with respect to the widget. 2973 * @width_return: Returns the width of the cell. 2974 * @height_return: Returns the height of the cell. 2975 * 2976 * Computes the data about this cell. 2977 **/ 2978 void 2979 e_tree_get_cell_geometry (ETree *tree, 2980 gint row, 2981 gint col, 2982 gint *x_return, 2983 gint *y_return, 2984 gint *width_return, 2985 gint *height_return) 2986 { 2987 GtkAdjustment *adjustment; 2988 GtkScrollable *scrollable; 2989 2990 g_return_if_fail (E_IS_TREE (tree)); 2991 g_return_if_fail (row >= 0); 2992 g_return_if_fail (col >= 0); 2993 2994 /* FIXME it would be nice if it could handle a NULL row_return or 2995 * col_return gracefully. */ 2996 2997 e_table_item_get_cell_geometry ( 2998 E_TABLE_ITEM (tree->priv->item), 2999 &row, &col, x_return, y_return, 3000 width_return, height_return); 3001 3002 scrollable = GTK_SCROLLABLE (tree->priv->table_canvas); 3003 3004 if (x_return) { 3005 adjustment = gtk_scrollable_get_hadjustment (scrollable); 3006 (*x_return) -= gtk_adjustment_get_value (adjustment); 3007 } 3008 3009 if (y_return) { 3010 adjustment = gtk_scrollable_get_vadjustment (scrollable); 3011 (*y_return) -= gtk_adjustment_get_value (adjustment); 3012 } 3013 } 3014 3015 static void 3016 et_drag_begin (GtkWidget *widget, 3017 GdkDragContext *context, 3018 ETree *et) 3019 { 3020 et->priv->is_dragging = TRUE; 3021 3022 g_signal_emit ( 3023 et, 3024 et_signals[TREE_DRAG_BEGIN], 0, 3025 et->priv->drag_row, 3026 et->priv->drag_path, 3027 et->priv->drag_col, 3028 context); 3029 } 3030 3031 static void 3032 et_drag_end (GtkWidget *widget, 3033 GdkDragContext *context, 3034 ETree *et) 3035 { 3036 et->priv->is_dragging = FALSE; 3037 3038 g_signal_emit ( 3039 et, 3040 et_signals[TREE_DRAG_END], 0, 3041 et->priv->drag_row, 3042 et->priv->drag_path, 3043 et->priv->drag_col, 3044 context); 3045 } 3046 3047 static void 3048 et_drag_data_get (GtkWidget *widget, 3049 GdkDragContext *context, 3050 GtkSelectionData *selection_data, 3051 guint info, 3052 guint time, 3053 ETree *et) 3054 { 3055 g_signal_emit ( 3056 et, 3057 et_signals[TREE_DRAG_DATA_GET], 0, 3058 et->priv->drag_row, 3059 et->priv->drag_path, 3060 et->priv->drag_col, 3061 context, 3062 selection_data, 3063 info, 3064 time); 3065 } 3066 3067 static void 3068 et_drag_data_delete (GtkWidget *widget, 3069 GdkDragContext *context, 3070 ETree *et) 3071 { 3072 g_signal_emit ( 3073 et, 3074 et_signals[TREE_DRAG_DATA_DELETE], 0, 3075 et->priv->drag_row, 3076 et->priv->drag_path, 3077 et->priv->drag_col, 3078 context); 3079 } 3080 3081 static gboolean 3082 do_drag_motion (ETree *et, 3083 GdkDragContext *context, 3084 gint x, 3085 gint y, 3086 guint time) 3087 { 3088 gboolean ret_val = FALSE; 3089 gint row, col; 3090 ETreePath path; 3091 3092 e_tree_get_cell_at (et, x, y, &row, &col); 3093 3094 if (row != et->priv->drop_row && col != et->priv->drop_col) {
The left operand of '!=' is a garbage value
(emitted by clang-analyzer)

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

The left operand of '!=' is a garbage value
(emitted by clang-analyzer)

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

3095 g_signal_emit ( 3096 et, et_signals[TREE_DRAG_LEAVE], 0, 3097 et->priv->drop_row, 3098 et->priv->drop_path, 3099 et->priv->drop_col, 3100 context, 3101 time); 3102 } 3103 3104 path = e_tree_table_adapter_node_at_row (et->priv->etta, row); 3105 3106 et->priv->drop_row = row; 3107 et->priv->drop_path = path; 3108 et->priv->drop_col = col; 3109 g_signal_emit ( 3110 et, et_signals[TREE_DRAG_MOTION], 0, 3111 et->priv->drop_row, 3112 et->priv->drop_path, 3113 et->priv->drop_col, 3114 context, 3115 x, y, 3116 time, 3117 &ret_val); 3118 3119 return ret_val; 3120 } 3121 3122 static gboolean 3123 scroll_timeout (gpointer data) 3124 { 3125 ETree *et = data; 3126 gint dx = 0, dy = 0; 3127 GtkAdjustment *adjustment; 3128 GtkScrollable *scrollable; 3129 gdouble old_h_value; 3130 gdouble new_h_value; 3131 gdouble old_v_value; 3132 gdouble new_v_value; 3133 gdouble page_size; 3134 gdouble lower; 3135 gdouble upper; 3136 3137 if (et->priv->scroll_direction & ET_SCROLL_DOWN) 3138 dy += 20; 3139 if (et->priv->scroll_direction & ET_SCROLL_UP) 3140 dy -= 20; 3141 3142 if (et->priv->scroll_direction & ET_SCROLL_RIGHT) 3143 dx += 20; 3144 if (et->priv->scroll_direction & ET_SCROLL_LEFT) 3145 dx -= 20; 3146 3147 scrollable = GTK_SCROLLABLE (et->priv->table_canvas); 3148 3149 adjustment = gtk_scrollable_get_hadjustment (scrollable); 3150 3151 page_size = gtk_adjustment_get_page_size (adjustment); 3152 lower = gtk_adjustment_get_lower (adjustment); 3153 upper = gtk_adjustment_get_upper (adjustment); 3154 3155 old_h_value = gtk_adjustment_get_value (adjustment); 3156 new_h_value = CLAMP (old_h_value + dx, lower, upper - page_size); 3157 3158 gtk_adjustment_set_value (adjustment, new_h_value); 3159 3160 adjustment = gtk_scrollable_get_vadjustment (scrollable); 3161 3162 page_size = gtk_adjustment_get_page_size (adjustment); 3163 lower = gtk_adjustment_get_lower (adjustment); 3164 upper = gtk_adjustment_get_upper (adjustment); 3165 3166 old_v_value = gtk_adjustment_get_value (adjustment); 3167 new_v_value = CLAMP (old_v_value + dy, lower, upper - page_size); 3168 3169 gtk_adjustment_set_value (adjustment, new_v_value); 3170 3171 if (new_h_value != old_h_value || new_v_value != old_v_value) 3172 do_drag_motion ( 3173 et, 3174 et->priv->last_drop_context, 3175 et->priv->last_drop_x, 3176 et->priv->last_drop_y, 3177 et->priv->last_drop_time); 3178 3179 return TRUE; 3180 } 3181 3182 static void 3183 scroll_on (ETree *et, 3184 guint scroll_direction) 3185 { 3186 if (et->priv->scroll_idle_id == 0 || 3187 scroll_direction != et->priv->scroll_direction) { 3188 if (et->priv->scroll_idle_id != 0) 3189 g_source_remove (et->priv->scroll_idle_id); 3190 et->priv->scroll_direction = scroll_direction; 3191 et->priv->scroll_idle_id = g_timeout_add (100, scroll_timeout, et); 3192 } 3193 } 3194 3195 static void 3196 scroll_off (ETree *et) 3197 { 3198 if (et->priv->scroll_idle_id) { 3199 g_source_remove (et->priv->scroll_idle_id); 3200 et->priv->scroll_idle_id = 0; 3201 } 3202 } 3203 3204 static gboolean 3205 hover_timeout (gpointer data) 3206 { 3207 ETree *et = data; 3208 gint x = et->priv->hover_x; 3209 gint y = et->priv->hover_y; 3210 gint row, col; 3211 ETreePath path; 3212 3213 e_tree_get_cell_at (et, x, y, &row, &col); 3214 3215 path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
Function call argument is an uninitialized value
(emitted by clang-analyzer)

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

Function call argument is an uninitialized value
(emitted by clang-analyzer)

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

3216 if (path && e_tree_model_node_is_expandable (et->priv->model, path)) { 3217 if (!e_tree_table_adapter_node_is_expanded (et->priv->etta, path)) { 3218 if (e_tree_model_has_save_id (et->priv->model) && 3219 e_tree_model_has_get_node_by_id (et->priv->model)) 3220 et->priv->expanded_list = g_list_prepend ( 3221 et->priv->expanded_list, 3222 e_tree_model_get_save_id ( 3223 et->priv->model, path)); 3224 3225 e_tree_table_adapter_node_set_expanded ( 3226 et->priv->etta, path, TRUE); 3227 } 3228 } 3229 3230 return TRUE; 3231 } 3232 3233 static void 3234 hover_on (ETree *et, 3235 gint x, 3236 gint y) 3237 { 3238 et->priv->hover_x = x; 3239 et->priv->hover_y = y; 3240 if (et->priv->hover_idle_id != 0) 3241 g_source_remove (et->priv->hover_idle_id); 3242 et->priv->hover_idle_id = g_timeout_add (500, hover_timeout, et); 3243 } 3244 3245 static void 3246 hover_off (ETree *et) 3247 { 3248 if (et->priv->hover_idle_id) { 3249 g_source_remove (et->priv->hover_idle_id); 3250 et->priv->hover_idle_id = 0; 3251 } 3252 } 3253 3254 static void 3255 collapse_drag (ETree *et, 3256 ETreePath drop) 3257 { 3258 GList *list; 3259 3260 /* We only want to leave open parents of the node dropped in. 3261 * Not the node itself. */ 3262 if (drop) { 3263 drop = e_tree_model_node_get_parent (et->priv->model, drop); 3264 } 3265 3266 for (list = et->priv->expanded_list; list; list = list->next) { 3267 gchar *save_id = list->data; 3268 ETreePath path; 3269 3270 path = e_tree_model_get_node_by_id (et->priv->model, save_id); 3271 if (path) { 3272 ETreePath search; 3273 gboolean found = FALSE; 3274 3275 for (search = drop; search; 3276 search = e_tree_model_node_get_parent ( 3277 et->priv->model, search)) { 3278 if (path == search) { 3279 found = TRUE; 3280 break; 3281 } 3282 } 3283 3284 if (!found) 3285 e_tree_table_adapter_node_set_expanded ( 3286 et->priv->etta, path, FALSE); 3287 } 3288 g_free (save_id); 3289 } 3290 g_list_free (et->priv->expanded_list); 3291 et->priv->expanded_list = NULL; 3292 } 3293 3294 static void 3295 context_destroyed (gpointer data, 3296 GObject *ctx) 3297 { 3298 ETree *et = data; 3299 if (et->priv) { 3300 et->priv->last_drop_x = 0; 3301 et->priv->last_drop_y = 0; 3302 et->priv->last_drop_time = 0; 3303 et->priv->last_drop_context = NULL; 3304 collapse_drag (et, NULL); 3305 scroll_off (et); 3306 hover_off (et); 3307 } 3308 g_object_unref (et); 3309 } 3310 3311 static void 3312 context_connect (ETree *et, 3313 GdkDragContext *context) 3314 { 3315 if (context == et->priv->last_drop_context) 3316 return; 3317 3318 if (et->priv->last_drop_context) 3319 g_object_weak_unref ( 3320 G_OBJECT (et->priv->last_drop_context), 3321 context_destroyed, et); 3322 else 3323 g_object_ref (et); 3324 3325 g_object_weak_ref (G_OBJECT (context), context_destroyed, et); 3326 } 3327 3328 static void 3329 et_drag_leave (GtkWidget *widget, 3330 GdkDragContext *context, 3331 guint time, 3332 ETree *et) 3333 { 3334 g_signal_emit ( 3335 et, 3336 et_signals[TREE_DRAG_LEAVE], 0, 3337 et->priv->drop_row, 3338 et->priv->drop_path, 3339 et->priv->drop_col, 3340 context, 3341 time); 3342 et->priv->drop_row = -1; 3343 et->priv->drop_col = -1; 3344 3345 scroll_off (et); 3346 hover_off (et); 3347 } 3348 3349 static gboolean 3350 et_drag_motion (GtkWidget *widget, 3351 GdkDragContext *context, 3352 gint x, 3353 gint y, 3354 guint time, 3355 ETree *et) 3356 { 3357 GtkAllocation allocation; 3358 gint ret_val; 3359 guint direction = 0; 3360 3361 et->priv->last_drop_x = x; 3362 et->priv->last_drop_y = y; 3363 et->priv->last_drop_time = time; 3364 context_connect (et, context); 3365 et->priv->last_drop_context = context; 3366 3367 if (et->priv->hover_idle_id != 0) { 3368 if (abs (et->priv->hover_x - x) > 3 || 3369 abs (et->priv->hover_y - y) > 3) { 3370 hover_on (et, x, y); 3371 } 3372 } else { 3373 hover_on (et, x, y); 3374 } 3375 3376 ret_val = do_drag_motion (et, context, x, y, time); 3377 3378 gtk_widget_get_allocation (widget, &allocation); 3379 3380 if (y < 20) 3381 direction |= ET_SCROLL_UP; 3382 if (y > allocation.height - 20) 3383 direction |= ET_SCROLL_DOWN; 3384 if (x < 20) 3385 direction |= ET_SCROLL_LEFT; 3386 if (x > allocation.width - 20) 3387 direction |= ET_SCROLL_RIGHT; 3388 3389 if (direction != 0) 3390 scroll_on (et, direction); 3391 else 3392 scroll_off (et); 3393 3394 return ret_val; 3395 } 3396 3397 static gboolean 3398 et_drag_drop (GtkWidget *widget, 3399 GdkDragContext *context, 3400 gint x, 3401 gint y, 3402 guint time, 3403 ETree *et) 3404 { 3405 gboolean ret_val = FALSE; 3406 gint row, col; 3407 ETreePath path; 3408 3409 e_tree_get_cell_at (et, x, y, &row, &col); 3410 3411 path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
Function call argument is an uninitialized value
(emitted by clang-analyzer)

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

Function call argument is an uninitialized value
(emitted by clang-analyzer)

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

3412 3413 if (row != et->priv->drop_row && col != et->priv->drop_row) { 3414 g_signal_emit ( 3415 et, et_signals[TREE_DRAG_LEAVE], 0, 3416 et->priv->drop_row, 3417 et->priv->drop_path, 3418 et->priv->drop_col, 3419 context, 3420 time); 3421 g_signal_emit ( 3422 et, et_signals[TREE_DRAG_MOTION], 0, 3423 row, 3424 path, 3425 col, 3426 context, 3427 x, 3428 y, 3429 time, 3430 &ret_val); 3431 } 3432 et->priv->drop_row = row; 3433 et->priv->drop_path = path; 3434 et->priv->drop_col = col; 3435 3436 g_signal_emit ( 3437 et, et_signals[TREE_DRAG_DROP], 0, 3438 et->priv->drop_row, 3439 et->priv->drop_path, 3440 et->priv->drop_col, 3441 context, 3442 x, 3443 y, 3444 time, 3445 &ret_val); 3446 3447 et->priv->drop_row = -1; 3448 et->priv->drop_path = NULL; 3449 et->priv->drop_col = -1; 3450 3451 collapse_drag (et, path); 3452 3453 scroll_off (et); 3454 return ret_val; 3455 } 3456 3457 static void 3458 et_drag_data_received (GtkWidget *widget, 3459 GdkDragContext *context, 3460 gint x, 3461 gint y, 3462 GtkSelectionData *selection_data, 3463 guint info, 3464 guint time, 3465 ETree *et) 3466 { 3467 gint row, col; 3468 ETreePath path; 3469 3470 e_tree_get_cell_at (et, x, y, &row, &col); 3471 3472 path = e_tree_table_adapter_node_at_row (et->priv->etta, row);
Function call argument is an uninitialized value
(emitted by clang-analyzer)

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

Function call argument is an uninitialized value
(emitted by clang-analyzer)

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

3473 g_signal_emit ( 3474 et, et_signals[TREE_DRAG_DATA_RECEIVED], 0, 3475 row, 3476 path, 3477 col, 3478 context, 3479 x, 3480 y, 3481 selection_data, 3482 info, 3483 time); 3484 } 3485 3486 static void 3487 e_tree_class_init (ETreeClass *class) 3488 { 3489 GObjectClass *object_class; 3490 GtkWidgetClass *widget_class; 3491 3492 g_type_class_add_private (class, sizeof (ETreePrivate)); 3493 3494 object_class = G_OBJECT_CLASS (class); 3495 object_class->dispose = et_dispose; 3496 object_class->set_property = et_set_property; 3497 object_class->get_property = et_get_property; 3498 3499 widget_class = GTK_WIDGET_CLASS (class); 3500 widget_class->grab_focus = et_grab_focus; 3501 widget_class->unrealize = et_unrealize; 3502 widget_class->style_set = et_canvas_style_set; 3503 widget_class->focus = et_focus; 3504 3505 class->start_drag = et_real_start_drag; 3506 3507 et_signals[CURSOR_CHANGE] = g_signal_new ( 3508 "cursor_change", 3509 G_OBJECT_CLASS_TYPE (object_class), 3510 G_SIGNAL_RUN_LAST, 3511 G_STRUCT_OFFSET (ETreeClass, cursor_change), 3512 NULL, NULL, 3513 e_marshal_NONE__INT_POINTER, 3514 G_TYPE_NONE, 2, 3515 G_TYPE_INT, 3516 G_TYPE_POINTER); 3517 3518 et_signals[CURSOR_ACTIVATED] = g_signal_new ( 3519 "cursor_activated", 3520 G_OBJECT_CLASS_TYPE (object_class), 3521 G_SIGNAL_RUN_LAST, 3522 G_STRUCT_OFFSET (ETreeClass, cursor_activated), 3523 NULL, NULL, 3524 e_marshal_NONE__INT_POINTER, 3525 G_TYPE_NONE, 2, 3526 G_TYPE_INT, 3527 G_TYPE_POINTER); 3528 3529 et_signals[SELECTION_CHANGE] = g_signal_new ( 3530 "selection_change", 3531 G_OBJECT_CLASS_TYPE (object_class), 3532 G_SIGNAL_RUN_LAST, 3533 G_STRUCT_OFFSET (ETreeClass, selection_change), 3534 NULL, NULL, 3535 g_cclosure_marshal_VOID__VOID, 3536 G_TYPE_NONE, 0); 3537 3538 et_signals[DOUBLE_CLICK] = g_signal_new ( 3539 "double_click", 3540 G_OBJECT_CLASS_TYPE (object_class), 3541 G_SIGNAL_RUN_LAST, 3542 G_STRUCT_OFFSET (ETreeClass, double_click), 3543 NULL, NULL, 3544 e_marshal_NONE__INT_POINTER_INT_BOXED, 3545 G_TYPE_NONE, 4, 3546 G_TYPE_INT, 3547 G_TYPE_POINTER, 3548 G_TYPE_INT, 3549 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3550 3551 et_signals[RIGHT_CLICK] = g_signal_new ( 3552 "right_click", 3553 G_OBJECT_CLASS_TYPE (object_class), 3554 G_SIGNAL_RUN_LAST, 3555 G_STRUCT_OFFSET (ETreeClass, right_click), 3556 g_signal_accumulator_true_handled, NULL, 3557 e_marshal_BOOLEAN__INT_POINTER_INT_BOXED, 3558 G_TYPE_BOOLEAN, 4, 3559 G_TYPE_INT, 3560 G_TYPE_POINTER, 3561 G_TYPE_INT, 3562 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3563 3564 et_signals[CLICK] = g_signal_new ( 3565 "click", 3566 G_OBJECT_CLASS_TYPE (object_class), 3567 G_SIGNAL_RUN_LAST, 3568 G_STRUCT_OFFSET (ETreeClass, click), 3569 g_signal_accumulator_true_handled, NULL, 3570 e_marshal_BOOLEAN__INT_POINTER_INT_BOXED, 3571 G_TYPE_BOOLEAN, 4, 3572 G_TYPE_INT, 3573 G_TYPE_POINTER, 3574 G_TYPE_INT, 3575 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3576 3577 et_signals[KEY_PRESS] = g_signal_new ( 3578 "key_press", 3579 G_OBJECT_CLASS_TYPE (object_class), 3580 G_SIGNAL_RUN_LAST, 3581 G_STRUCT_OFFSET (ETreeClass, key_press), 3582 g_signal_accumulator_true_handled, NULL, 3583 e_marshal_BOOLEAN__INT_POINTER_INT_BOXED, 3584 G_TYPE_BOOLEAN, 4, 3585 G_TYPE_INT, 3586 G_TYPE_POINTER, 3587 G_TYPE_INT, 3588 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3589 3590 et_signals[START_DRAG] = g_signal_new ( 3591 "start_drag", 3592 G_OBJECT_CLASS_TYPE (object_class), 3593 G_SIGNAL_RUN_LAST, 3594 G_STRUCT_OFFSET (ETreeClass, start_drag), 3595 NULL, NULL, 3596 e_marshal_NONE__INT_POINTER_INT_BOXED, 3597 G_TYPE_NONE, 4, 3598 G_TYPE_INT, 3599 G_TYPE_POINTER, 3600 G_TYPE_INT, 3601 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3602 3603 et_signals[STATE_CHANGE] = g_signal_new ( 3604 "state_change", 3605 G_OBJECT_CLASS_TYPE (object_class), 3606 G_SIGNAL_RUN_LAST, 3607 G_STRUCT_OFFSET (ETreeClass, state_change), 3608 NULL, NULL, 3609 g_cclosure_marshal_VOID__VOID, 3610 G_TYPE_NONE, 0); 3611 3612 et_signals[WHITE_SPACE_EVENT] = g_signal_new ( 3613 "white_space_event", 3614 G_OBJECT_CLASS_TYPE (object_class), 3615 G_SIGNAL_RUN_LAST, 3616 G_STRUCT_OFFSET (ETreeClass, white_space_event), 3617 g_signal_accumulator_true_handled, NULL, 3618 e_marshal_BOOLEAN__POINTER, 3619 G_TYPE_BOOLEAN, 1, 3620 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3621 3622 et_signals[TREE_DRAG_BEGIN] = g_signal_new ( 3623 "tree_drag_begin", 3624 G_OBJECT_CLASS_TYPE (object_class), 3625 G_SIGNAL_RUN_LAST, 3626 G_STRUCT_OFFSET (ETreeClass, tree_drag_begin), 3627 NULL, NULL, 3628 e_marshal_NONE__INT_POINTER_INT_BOXED, 3629 G_TYPE_NONE, 4, 3630 G_TYPE_INT, 3631 G_TYPE_POINTER, 3632 G_TYPE_INT, 3633 GDK_TYPE_DRAG_CONTEXT); 3634 3635 et_signals[TREE_DRAG_END] = g_signal_new ( 3636 "tree_drag_end", 3637 G_OBJECT_CLASS_TYPE (object_class), 3638 G_SIGNAL_RUN_LAST, 3639 G_STRUCT_OFFSET (ETreeClass, tree_drag_end), 3640 NULL, NULL, 3641 e_marshal_NONE__INT_POINTER_INT_BOXED, 3642 G_TYPE_NONE, 4, 3643 G_TYPE_INT, 3644 G_TYPE_POINTER, 3645 G_TYPE_INT, 3646 GDK_TYPE_DRAG_CONTEXT); 3647 3648 et_signals[TREE_DRAG_DATA_GET] = g_signal_new ( 3649 "tree_drag_data_get", 3650 G_OBJECT_CLASS_TYPE (object_class), 3651 G_SIGNAL_RUN_LAST, 3652 G_STRUCT_OFFSET (ETreeClass, tree_drag_data_get), 3653 NULL, NULL, 3654 e_marshal_NONE__INT_POINTER_INT_OBJECT_BOXED_UINT_UINT, 3655 G_TYPE_NONE, 7, 3656 G_TYPE_INT, 3657 G_TYPE_POINTER, 3658 G_TYPE_INT, 3659 GDK_TYPE_DRAG_CONTEXT, 3660 GTK_TYPE_SELECTION_DATA | G_SIGNAL_TYPE_STATIC_SCOPE, 3661 G_TYPE_UINT, 3662 G_TYPE_UINT); 3663 3664 et_signals[TREE_DRAG_DATA_DELETE] = g_signal_new ( 3665 "tree_drag_data_delete", 3666 G_OBJECT_CLASS_TYPE (object_class), 3667 G_SIGNAL_RUN_LAST, 3668 G_STRUCT_OFFSET (ETreeClass, tree_drag_data_delete), 3669 NULL, NULL, 3670 e_marshal_NONE__INT_POINTER_INT_OBJECT, 3671 G_TYPE_NONE, 4, 3672 G_TYPE_INT, 3673 G_TYPE_POINTER, 3674 G_TYPE_INT, 3675 GDK_TYPE_DRAG_CONTEXT); 3676 3677 et_signals[TREE_DRAG_LEAVE] = g_signal_new ( 3678 "tree_drag_leave", 3679 G_OBJECT_CLASS_TYPE (object_class), 3680 G_SIGNAL_RUN_LAST, 3681 G_STRUCT_OFFSET (ETreeClass, tree_drag_leave), 3682 NULL, NULL, 3683 e_marshal_NONE__INT_POINTER_INT_OBJECT_UINT, 3684 G_TYPE_NONE, 5, 3685 G_TYPE_INT, 3686 G_TYPE_POINTER, 3687 G_TYPE_INT, 3688 GDK_TYPE_DRAG_CONTEXT, 3689 G_TYPE_UINT); 3690 3691 et_signals[TREE_DRAG_MOTION] = g_signal_new ( 3692 "tree_drag_motion", 3693 G_OBJECT_CLASS_TYPE (object_class), 3694 G_SIGNAL_RUN_LAST, 3695 G_STRUCT_OFFSET (ETreeClass, tree_drag_motion), 3696 NULL, NULL, 3697 e_marshal_BOOLEAN__INT_POINTER_INT_OBJECT_INT_INT_UINT, 3698 G_TYPE_BOOLEAN, 7, 3699 G_TYPE_INT, 3700 G_TYPE_POINTER, 3701 G_TYPE_INT, 3702 GDK_TYPE_DRAG_CONTEXT, 3703 G_TYPE_INT, 3704 G_TYPE_INT, 3705 G_TYPE_UINT); 3706 3707 et_signals[TREE_DRAG_DROP] = g_signal_new ( 3708 "tree_drag_drop", 3709 G_OBJECT_CLASS_TYPE (object_class), 3710 G_SIGNAL_RUN_LAST, 3711 G_STRUCT_OFFSET (ETreeClass, tree_drag_drop), 3712 NULL, NULL, 3713 e_marshal_BOOLEAN__INT_POINTER_INT_OBJECT_INT_INT_UINT, 3714 G_TYPE_BOOLEAN, 7, 3715 G_TYPE_INT, 3716 G_TYPE_POINTER, 3717 G_TYPE_INT, 3718 GDK_TYPE_DRAG_CONTEXT, 3719 G_TYPE_INT, 3720 G_TYPE_INT, 3721 G_TYPE_UINT); 3722 3723 et_signals[TREE_DRAG_DATA_RECEIVED] = g_signal_new ( 3724 "tree_drag_data_received", 3725 G_OBJECT_CLASS_TYPE (object_class), 3726 G_SIGNAL_RUN_LAST, 3727 G_STRUCT_OFFSET (ETreeClass, tree_drag_data_received), 3728 NULL, NULL, 3729 e_marshal_NONE__INT_POINTER_INT_OBJECT_INT_INT_BOXED_UINT_UINT, 3730 G_TYPE_NONE, 9, 3731 G_TYPE_INT, 3732 G_TYPE_POINTER, 3733 G_TYPE_INT, 3734 GDK_TYPE_DRAG_CONTEXT, 3735 G_TYPE_INT, 3736 G_TYPE_INT, 3737 GTK_TYPE_SELECTION_DATA, 3738 G_TYPE_UINT, 3739 G_TYPE_UINT); 3740 3741 g_object_class_install_property ( 3742 object_class, 3743 PROP_LENGTH_THRESHOLD, 3744 g_param_spec_int ( 3745 "length_threshold", 3746 "Length Threshold", 3747 "Length Threshold", 3748 0, G_MAXINT, 0, 3749 G_PARAM_WRITABLE)); 3750 3751 g_object_class_install_property ( 3752 object_class, 3753 PROP_HORIZONTAL_DRAW_GRID, 3754 g_param_spec_boolean ( 3755 "horizontal_draw_grid", 3756 "Horizontal Draw Grid", 3757 "Horizontal Draw Grid", 3758 FALSE, 3759 G_PARAM_WRITABLE)); 3760 3761 g_object_class_install_property ( 3762 object_class, 3763 PROP_VERTICAL_DRAW_GRID, 3764 g_param_spec_boolean ( 3765 "vertical_draw_grid", 3766 "Vertical Draw Grid", 3767 "Vertical Draw Grid", 3768 FALSE, 3769 G_PARAM_WRITABLE)); 3770 3771 g_object_class_install_property ( 3772 object_class, 3773 PROP_DRAW_FOCUS, 3774 g_param_spec_boolean ( 3775 "drawfocus", 3776 "Draw focus", 3777 "Draw focus", 3778 FALSE, 3779 G_PARAM_WRITABLE)); 3780 3781 g_object_class_install_property ( 3782 object_class, 3783 PROP_ETTA, 3784 g_param_spec_object ( 3785 "ETreeTableAdapter", 3786 "ETree table adapter", 3787 "ETree table adapter", 3788 E_TYPE_TREE_TABLE_ADAPTER, 3789 G_PARAM_READABLE)); 3790 3791 g_object_class_install_property ( 3792 object_class, 3793 PROP_UNIFORM_ROW_HEIGHT, 3794 g_param_spec_boolean ( 3795 "uniform_row_height", 3796 "Uniform row height", 3797 "Uniform row height", 3798 FALSE, 3799 G_PARAM_READWRITE)); 3800 3801 g_object_class_install_property ( 3802 object_class, 3803 PROP_ALWAYS_SEARCH, 3804 g_param_spec_boolean ( 3805 "always_search", 3806 "Always search", 3807 "Always search", 3808 FALSE, 3809 G_PARAM_READWRITE)); 3810 3811 gtk_widget_class_install_style_property ( 3812 widget_class, 3813 g_param_spec_int ( 3814 "expander_size", 3815 "Expander Size", 3816 "Size of the expander arrow", 3817 0, G_MAXINT, 10, 3818 G_PARAM_READABLE)); 3819 3820 gtk_widget_class_install_style_property ( 3821 widget_class, 3822 g_param_spec_int ( 3823 "vertical-spacing", 3824 "Vertical Row Spacing", 3825 "Vertical space between rows. " 3826 "It is added to top and to bottom of a row", 3827 0, G_MAXINT, 3, 3828 G_PARAM_READABLE | 3829 G_PARAM_STATIC_STRINGS)); 3830 3831 /* Scrollable interface */ 3832 g_object_class_override_property ( 3833 object_class, PROP_HADJUSTMENT, "hadjustment"); 3834 g_object_class_override_property ( 3835 object_class, PROP_VADJUSTMENT, "vadjustment"); 3836 g_object_class_override_property ( 3837 object_class, PROP_HSCROLL_POLICY, "hscroll-policy"); 3838 g_object_class_override_property ( 3839 object_class, PROP_VSCROLL_POLICY, "vscroll-policy"); 3840 3841 gal_a11y_e_tree_init (); 3842 } 3843 3844 static void 3845 tree_size_allocate (GtkWidget *widget, 3846 GtkAllocation *alloc, 3847 ETree *tree) 3848 { 3849 gdouble width; 3850 3851 g_return_if_fail (tree != NULL); 3852 g_return_if_fail (tree->priv != NULL); 3853 g_return_if_fail (tree->priv->info_text != NULL); 3854 3855 gnome_canvas_get_scroll_region ( 3856 GNOME_CANVAS (tree->priv->table_canvas), 3857 NULL, NULL, &width, NULL); 3858 3859 width -= 60.0; 3860 3861 g_object_set ( 3862 tree->priv->info_text, "width", width, 3863 "clip_width", width, NULL); 3864 } 3865 3866 /** 3867 * e_tree_set_info_message: 3868 * @tree: #ETree instance 3869 * @info_message: Message to set. Can be NULL. 3870 * 3871 * Creates an info message in table area, or removes old. 3872 **/ 3873 void 3874 e_tree_set_info_message (ETree *tree, 3875 const gchar *info_message) 3876 { 3877 GtkAllocation allocation; 3878 GtkWidget *widget; 3879 3880 g_return_if_fail (tree != NULL); 3881 g_return_if_fail (tree->priv != NULL); 3882 3883 if (!tree->priv->info_text && (!info_message || !*info_message)) 3884 return; 3885 3886 if (!info_message || !*info_message) { 3887 g_signal_handler_disconnect (tree, tree->priv->info_text_resize_id); 3888 g_object_run_dispose (G_OBJECT (tree->priv->info_text)); 3889 tree->priv->info_text = NULL; 3890 return; 3891 } 3892 3893 widget = GTK_WIDGET (tree->priv->table_canvas); 3894 gtk_widget_get_allocation (widget, &allocation); 3895 3896 if (!tree->priv->info_text) { 3897 if (allocation.width > 60) { 3898 tree->priv->info_text = gnome_canvas_item_new ( 3899 GNOME_CANVAS_GROUP (gnome_canvas_root (tree->priv->table_canvas)), 3900 e_text_get_type (), 3901 "line_wrap", TRUE, 3902 "clip", TRUE, 3903 "justification", GTK_JUSTIFY_LEFT, 3904 "text", info_message, 3905 "width", (gdouble) allocation.width - 60.0, 3906 "clip_width", (gdouble) allocation.width - 60.0, 3907 NULL); 3908 3909 e_canvas_item_move_absolute (tree->priv->info_text, 30, 30); 3910 3911 tree->priv->info_text_resize_id = g_signal_connect ( 3912 tree, "size_allocate", 3913 G_CALLBACK (tree_size_allocate), tree); 3914 } 3915 } else 3916 gnome_canvas_item_set (tree->priv->info_text, "text", info_message, NULL); 3917 } 3918 3919 void 3920 e_tree_freeze_state_change (ETree *tree) 3921 { 3922 g_return_if_fail (tree != NULL); 3923 3924 tree->priv->state_change_freeze++; 3925 if (tree->priv->state_change_freeze == 1) 3926 tree->priv->state_changed = FALSE; 3927 3928 g_return_if_fail (tree->priv->state_change_freeze != 0); 3929 } 3930 3931 void 3932 e_tree_thaw_state_change (ETree *tree) 3933 { 3934 g_return_if_fail (tree != NULL); 3935 g_return_if_fail (tree->priv->state_change_freeze != 0); 3936 3937 tree->priv->state_change_freeze--; 3938 if (tree->priv->state_change_freeze == 0 && tree->priv->state_changed) { 3939 tree->priv->state_changed = FALSE; 3940 e_tree_state_change (tree); 3941 } 3942 }