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

Location Tool Test ID Function Issue
e-table.c:933:17 clang-analyzer The left operand of '==' is a garbage value
e-table.c:933:17 clang-analyzer The left operand of '==' is a garbage value
e-table.c:953:17 clang-analyzer The left operand of '==' is a garbage value
e-table.c:953:17 clang-analyzer The left operand of '==' is a garbage value
e-table.c:2747:6 clang-analyzer The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
e-table.c:2747:6 clang-analyzer The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
e-table.c:2751:5 clang-analyzer The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
e-table.c:2751:5 clang-analyzer The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
e-table.c:3230:10 clang-analyzer The left operand of '!=' is a garbage value
e-table.c:3230:10 clang-analyzer The left operand of '!=' is a garbage value
e-table.c:3265:2 clang-analyzer Function call argument is an uninitialized value
e-table.c:3265:2 clang-analyzer Function call argument is an uninitialized value
   1 /*
   2  * e-table.c - A graphical view of a Table.
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) version 3.
   8  *
   9  * This program is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  16  *
  17  *
  18  * Authors:
  19  *		Chris Lahey <clahey@ximian.com>
  20  *		Miguel de Icaza <miguel@ximian.com>
  21  *
  22  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  23  *
  24  */
  25 
  26 #ifdef HAVE_CONFIG_H
  27 #include <config.h>
  28 #endif
  29 
  30 #include <stdlib.h>
  31 #include <string.h>
  32 #include <stdio.h>
  33 
  34 #include <glib/gstdio.h>
  35 #include <gdk/gdkkeysyms.h>
  36 #include <gtk/gtk.h>
  37 #include <libgnomecanvas/libgnomecanvas.h>
  38 
  39 #include "gal-a11y-e-table.h"
  40 #include <glib/gi18n.h>
  41 #include "e-util/e-util.h"
  42 #include "misc/e-canvas.h"
  43 #include "misc/e-canvas-background.h"
  44 #include "misc/e-canvas-vbox.h"
  45 #include "e-util/e-unicode.h"
  46 
  47 #include "e-table.h"
  48 #include "e-table-click-to-add.h"
  49 #include "e-table-column-specification.h"
  50 #include "e-table-group-leaf.h"
  51 #include "e-table-header-item.h"
  52 #include "e-table-header-utils.h"
  53 #include "e-table-subset.h"
  54 #include "e-table-utils.h"
  55 
  56 #define COLUMN_HEADER_HEIGHT 16
  57 
  58 #define d(x)
  59 
  60 #if d(!)0
  61 #define e_table_item_leave_edit_(x) \
  62 	(e_table_item_leave_edit ((x)), \
  63 	 g_print ("%s: e_table_item_leave_edit\n", __FUNCTION__))
  64 #else
  65 #define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)))
  66 #endif
  67 
  68 enum {
  69 	CURSOR_CHANGE,
  70 	CURSOR_ACTIVATED,
  71 	SELECTION_CHANGE,
  72 	DOUBLE_CLICK,
  73 	RIGHT_CLICK,
  74 	CLICK,
  75 	KEY_PRESS,
  76 	START_DRAG,
  77 	STATE_CHANGE,
  78 	WHITE_SPACE_EVENT,
  79 
  80 	CUT_CLIPBOARD,
  81 	COPY_CLIPBOARD,
  82 	PASTE_CLIPBOARD,
  83 	SELECT_ALL,
  84 
  85 	TABLE_DRAG_BEGIN,
  86 	TABLE_DRAG_END,
  87 	TABLE_DRAG_DATA_GET,
  88 	TABLE_DRAG_DATA_DELETE,
  89 
  90 	TABLE_DRAG_LEAVE,
  91 	TABLE_DRAG_MOTION,
  92 	TABLE_DRAG_DROP,
  93 	TABLE_DRAG_DATA_RECEIVED,
  94 
  95 	LAST_SIGNAL
  96 };
  97 
  98 enum {
  99 	PROP_0,
 100 	PROP_LENGTH_THRESHOLD,
 101 	PROP_MODEL,
 102 	PROP_UNIFORM_ROW_HEIGHT,
 103 	PROP_ALWAYS_SEARCH,
 104 	PROP_USE_CLICK_TO_ADD,
 105 	PROP_HADJUSTMENT,
 106 	PROP_VADJUSTMENT,
 107 	PROP_HSCROLL_POLICY,
 108 	PROP_VSCROLL_POLICY
 109 };
 110 
 111 enum {
 112 	ET_SCROLL_UP = 1 << 0,
 113 	ET_SCROLL_DOWN = 1 << 1,
 114 	ET_SCROLL_LEFT = 1 << 2,
 115 	ET_SCROLL_RIGHT = 1 << 3
 116 };
 117 
 118 static guint et_signals[LAST_SIGNAL] = { 0 };
 119 
 120 static void e_table_fill_table (ETable *e_table, ETableModel *model);
 121 static gboolean changed_idle (gpointer data);
 122 
 123 static void et_grab_focus (GtkWidget *widget);
 124 
 125 static void et_drag_begin (GtkWidget *widget,
 126 			   GdkDragContext *context,
 127 			   ETable *et);
 128 static void et_drag_end (GtkWidget *widget,
 129 			 GdkDragContext *context,
 130 			 ETable *et);
 131 static void et_drag_data_get (GtkWidget *widget,
 132 			     GdkDragContext *context,
 133 			     GtkSelectionData *selection_data,
 134 			     guint info,
 135 			     guint time,
 136 			     ETable *et);
 137 static void et_drag_data_delete (GtkWidget *widget,
 138 				GdkDragContext *context,
 139 				ETable *et);
 140 
 141 static void et_drag_leave (GtkWidget *widget,
 142 			  GdkDragContext *context,
 143 			  guint time,
 144 			  ETable *et);
 145 static gboolean et_drag_motion (GtkWidget *widget,
 146 			       GdkDragContext *context,
 147 			       gint x,
 148 			       gint y,
 149 			       guint time,
 150 			       ETable *et);
 151 static gboolean et_drag_drop (GtkWidget *widget,
 152 			     GdkDragContext *context,
 153 			     gint x,
 154 			     gint y,
 155 			     guint time,
 156 			     ETable *et);
 157 static void et_drag_data_received (GtkWidget *widget,
 158 				  GdkDragContext *context,
 159 				  gint x,
 160 				  gint y,
 161 				  GtkSelectionData *selection_data,
 162 				  guint info,
 163 				  guint time,
 164 				  ETable *et);
 165 
 166 static gint et_focus (GtkWidget *container, GtkDirectionType direction);
 167 
 168 static void scroll_off (ETable *et);
 169 static void scroll_on (ETable *et, guint scroll_direction);
 170 
 171 G_DEFINE_TYPE_WITH_CODE (ETable, e_table, GTK_TYPE_TABLE,
 172 			 G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
 173 
 174 static void
 175 et_disconnect_model (ETable *et)
 176 {
 177 	if (et->model == NULL)
 178 		return;
 179 
 180 	if (et->table_model_change_id != 0)
 181 		g_signal_handler_disconnect (
 182 			et->model, et->table_model_change_id);
 183 	if (et->table_row_change_id != 0)
 184 		g_signal_handler_disconnect (
 185 			et->model, et->table_row_change_id);
 186 	if (et->table_cell_change_id != 0)
 187 		g_signal_handler_disconnect (
 188 			et->model, et->table_cell_change_id);
 189 	if (et->table_rows_inserted_id != 0)
 190 		g_signal_handler_disconnect (
 191 			et->model, et->table_rows_inserted_id);
 192 	if (et->table_rows_deleted_id != 0)
 193 		g_signal_handler_disconnect (
 194 			et->model, et->table_rows_deleted_id);
 195 
 196 	et->table_model_change_id = 0;
 197 	et->table_row_change_id = 0;
 198 	et->table_cell_change_id = 0;
 199 	et->table_rows_inserted_id = 0;
 200 	et->table_rows_deleted_id = 0;
 201 }
 202 
 203 static void
 204 e_table_state_change (ETable *et)
 205 {
 206 	if (et->state_change_freeze)
 207 		et->state_changed = TRUE;
 208 	else
 209 		g_signal_emit (et, et_signals[STATE_CHANGE], 0);
 210 }
 211 
 212 #define CHECK_HORIZONTAL(et) \
 213 	if ((et)->horizontal_scrolling || (et)->horizontal_resize) \
 214 		e_table_header_update_horizontal (et->header);
 215 
 216 static void
 217 clear_current_search_col (ETable *et)
 218 {
 219 	et->search_col_set = FALSE;
 220 }
 221 
 222 static ETableCol *
 223 current_search_col (ETable *et)
 224 {
 225 	if (!et->search_col_set) {
 226 		et->current_search_col =
 227 			e_table_util_calculate_current_search_col (
 228 				et->header,
 229 				et->full_header,
 230 				et->sort_info,
 231 				et->always_search);
 232 		et->search_col_set = TRUE;
 233 	}
 234 
 235 	return et->current_search_col;
 236 }
 237 
 238 static void
 239 et_get_preferred_width (GtkWidget *widget,
 240                         gint *minimum,
 241                         gint *natural)
 242 {
 243 	ETable *et = E_TABLE (widget);
 244 
 245 	GTK_WIDGET_CLASS (e_table_parent_class)->
 246 		get_preferred_width (widget, minimum, natural);
 247 
 248 	if (et->horizontal_resize) {
 249 		*minimum = MAX (*minimum, et->header_width);
 250 		*natural = MAX (*natural, et->header_width);
 251 	}
 252 }
 253 
 254 static void
 255 et_get_preferred_height (GtkWidget *widget,
 256                          gint *minimum,
 257                          gint *natural)
 258 {
 259 	GTK_WIDGET_CLASS (e_table_parent_class)->
 260 		get_preferred_height (widget, minimum, natural);
 261 }
 262 
 263 static void
 264 set_header_width (ETable *et)
 265 {
 266 	if (et->horizontal_resize) {
 267 		et->header_width = e_table_header_min_width (et->header);
 268 		gtk_widget_queue_resize (GTK_WIDGET (et));
 269 	}
 270 }
 271 
 272 static void
 273 structure_changed (ETableHeader *header,
 274                    ETable *et)
 275 {
 276 	e_table_state_change (et);
 277 	set_header_width (et);
 278 	clear_current_search_col (et);
 279 }
 280 
 281 static void
 282 expansion_changed (ETableHeader *header,
 283                    ETable *et)
 284 {
 285 	e_table_state_change (et);
 286 	set_header_width (et);
 287 }
 288 
 289 static void
 290 dimension_changed (ETableHeader *header,
 291                    gint total_width,
 292                    ETable *et)
 293 {
 294 	set_header_width (et);
 295 }
 296 
 297 static void
 298 disconnect_header (ETable *e_table)
 299 {
 300 	if (e_table->header == NULL)
 301 		return;
 302 
 303 	if (e_table->structure_change_id)
 304 		g_signal_handler_disconnect (
 305 			e_table->header, e_table->structure_change_id);
 306 	if (e_table->expansion_change_id)
 307 		g_signal_handler_disconnect (
 308 			e_table->header, e_table->expansion_change_id);
 309 	if (e_table->dimension_change_id)
 310 		g_signal_handler_disconnect (
 311 			e_table->header, e_table->dimension_change_id);
 312 
 313 	g_object_unref (e_table->header);
 314 	e_table->header = NULL;
 315 }
 316 
 317 static void
 318 connect_header (ETable *e_table,
 319                 ETableState *state)
 320 {
 321 	if (e_table->header != NULL)
 322 		disconnect_header (e_table);
 323 
 324 	e_table->header = e_table_state_to_header (
 325 		GTK_WIDGET (e_table), e_table->full_header, state);
 326 
 327 	e_table->structure_change_id = g_signal_connect (
 328 		e_table->header, "structure_change",
 329 		G_CALLBACK (structure_changed), e_table);
 330 	e_table->expansion_change_id = g_signal_connect (
 331 		e_table->header, "expansion_change",
 332 		G_CALLBACK (expansion_changed), e_table);
 333 	e_table->dimension_change_id = g_signal_connect (
 334 		e_table->header, "dimension_change",
 335 		G_CALLBACK (dimension_changed), e_table);
 336 }
 337 
 338 static void
 339 et_dispose (GObject *object)
 340 {
 341 	ETable *et = E_TABLE (object);
 342 
 343 	et_disconnect_model (et);
 344 
 345 	if (et->search) {
 346 		if (et->search_search_id)
 347 			g_signal_handler_disconnect (
 348 				et->search, et->search_search_id);
 349 		if (et->search_accept_id)
 350 			g_signal_handler_disconnect (
 351 				et->search, et->search_accept_id);
 352 		g_object_unref (et->search);
 353 		et->search = NULL;
 354 	}
 355 
 356 	if (et->group_info_change_id) {
 357 		g_signal_handler_disconnect (
 358 			et->sort_info, et->group_info_change_id);
 359 		et->group_info_change_id = 0;
 360 	}
 361 
 362 	if (et->sort_info_change_id) {
 363 		g_signal_handler_disconnect (
 364 			et->sort_info, et->sort_info_change_id);
 365 		et->sort_info_change_id = 0;
 366 	}
 367 
 368 	if (et->reflow_idle_id) {
 369 		g_source_remove (et->reflow_idle_id);
 370 		et->reflow_idle_id = 0;
 371 	}
 372 
 373 	scroll_off (et);
 374 
 375 	disconnect_header (et);
 376 
 377 	if (et->model) {
 378 		g_object_unref (et->model);
 379 		et->model = NULL;
 380 	}
 381 
 382 	if (et->full_header) {
 383 		g_object_unref (et->full_header);
 384 		et->full_header = NULL;
 385 	}
 386 
 387 	if (et->sort_info) {
 388 		g_object_unref (et->sort_info);
 389 		et->sort_info = NULL;
 390 	}
 391 
 392 	if (et->sorter) {
 393 		g_object_unref (et->sorter);
 394 		et->sorter = NULL;
 395 	}
 396 
 397 	if (et->selection) {
 398 		g_object_unref (et->selection);
 399 		et->selection = NULL;
 400 	}
 401 
 402 	if (et->spec) {
 403 		g_object_unref (et->spec);
 404 		et->spec = NULL;
 405 	}
 406 
 407 	if (et->header_canvas != NULL) {
 408 		gtk_widget_destroy (GTK_WIDGET (et->header_canvas));
 409 		et->header_canvas = NULL;
 410 	}
 411 
 412 	if (et->site != NULL) {
 413 		e_table_drag_source_unset (et);
 414 		et->site = NULL;
 415 	}
 416 
 417 	if (et->table_canvas != NULL) {
 418 		gtk_widget_destroy (GTK_WIDGET (et->table_canvas));
 419 		et->table_canvas = NULL;
 420 	}
 421 
 422 	if (et->rebuild_idle_id != 0) {
 423 		g_source_remove (et->rebuild_idle_id);
 424 		et->rebuild_idle_id = 0;
 425 	}
 426 
 427 	g_free (et->click_to_add_message);
 428 	et->click_to_add_message = NULL;
 429 
 430 	g_free (et->domain);
 431 	et->domain = NULL;
 432 
 433 	G_OBJECT_CLASS (e_table_parent_class)->dispose (object);
 434 }
 435 
 436 static void
 437 et_unrealize (GtkWidget *widget)
 438 {
 439 	scroll_off (E_TABLE (widget));
 440 
 441 	if (GTK_WIDGET_CLASS (e_table_parent_class)->unrealize)
 442 		GTK_WIDGET_CLASS (e_table_parent_class)->unrealize (widget);
 443 }
 444 
 445 static gboolean
 446 check_row (ETable *et,
 447            gint model_row,
 448            gint col,
 449            ETableSearchFunc search,
 450            gchar *string)
 451 {
 452 	gconstpointer value;
 453 
 454 	value = e_table_model_value_at (et->model, col, model_row);
 455 
 456 	return search (value, string);
 457 }
 458 
 459 static gboolean
 460 et_search_search (ETableSearch *search,
 461                   gchar *string,
 462                   ETableSearchFlags flags,
 463                   ETable *et)
 464 {
 465 	gint cursor;
 466 	gint rows;
 467 	gint i;
 468 	ETableCol *col = current_search_col (et);
 469 
 470 	if (col == NULL)
 471 		return FALSE;
 472 
 473 	rows = e_table_model_row_count (et->model);
 474 
 475 	g_object_get (
 476 		et->selection,
 477 		"cursor_row", &cursor,
 478 		NULL);
 479 
 480 	if ((flags & E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST) &&
 481 		cursor < rows && cursor >= 0 &&
 482 		check_row (et, cursor, col->col_idx, col->search, string))
 483 		return TRUE;
 484 
 485 	cursor = e_sorter_model_to_sorted (E_SORTER (et->sorter), cursor);
 486 
 487 	for (i = cursor + 1; i < rows; i++) {
 488 		gint model_row = e_sorter_sorted_to_model (E_SORTER (et->sorter), i);
 489 		if (check_row (et, model_row, col->col_idx, col->search, string)) {
 490 			e_selection_model_select_as_key_press (
 491 				E_SELECTION_MODEL (et->selection),
 492 				model_row, col->col_idx, GDK_CONTROL_MASK);
 493 			return TRUE;
 494 		}
 495 	}
 496 
 497 	for (i = 0; i < cursor; i++) {
 498 		gint model_row = e_sorter_sorted_to_model (E_SORTER (et->sorter), i);
 499 		if (check_row (et, model_row, col->col_idx, col->search, string)) {
 500 			e_selection_model_select_as_key_press (
 501 				E_SELECTION_MODEL (et->selection),
 502 				model_row, col->col_idx, GDK_CONTROL_MASK);
 503 			return TRUE;
 504 		}
 505 	}
 506 
 507 	cursor = e_sorter_sorted_to_model (E_SORTER (et->sorter), cursor);
 508 
 509 	/* Check if the cursor row is the only matching row. */
 510 	return (!(flags & E_TABLE_SEARCH_FLAGS_CHECK_CURSOR_FIRST) &&
 511 		cursor < rows && cursor >= 0 &&
 512 		check_row (et, cursor, col->col_idx, col->search, string));
 513 }
 514 
 515 static void
 516 et_search_accept (ETableSearch *search,
 517                   ETable *et)
 518 {
 519 	gint cursor;
 520 	ETableCol *col = current_search_col (et);
 521 
 522 	if (col == NULL)
 523 		return;
 524 
 525 	g_object_get (et->selection, "cursor_row", &cursor, NULL);
 526 
 527 	e_selection_model_select_as_key_press (
 528 		E_SELECTION_MODEL (et->selection), cursor, col->col_idx, 0);
 529 }
 530 
 531 static void
 532 init_search (ETable *e_table)
 533 {
 534 	if (e_table->search != NULL)
 535 		return;
 536 
 537 	e_table->search           = e_table_search_new ();
 538 
 539 	e_table->search_search_id = g_signal_connect (
 540 		e_table->search, "search",
 541 		G_CALLBACK (et_search_search), e_table);
 542 	e_table->search_accept_id = g_signal_connect (
 543 		e_table->search, "accept",
 544 		G_CALLBACK (et_search_accept), e_table);
 545 }
 546 
 547 static void
 548 et_finalize (GObject *object)
 549 {
 550 	ETable *et = E_TABLE (object);
 551 
 552 	g_free (et->click_to_add_message);
 553 	et->click_to_add_message = NULL;
 554 
 555 	g_free (et->domain);
 556 	et->domain = NULL;
 557 
 558 	G_OBJECT_CLASS (e_table_parent_class)->finalize (object);
 559 }
 560 
 561 static void
 562 e_table_init (ETable *e_table)
 563 {
 564 	gtk_widget_set_can_focus (GTK_WIDGET (e_table), TRUE);
 565 
 566 	gtk_table_set_homogeneous (GTK_TABLE (e_table), FALSE);
 567 
 568 	e_table->sort_info              = NULL;
 569 	e_table->group_info_change_id   = 0;
 570 	e_table->sort_info_change_id    = 0;
 571 	e_table->structure_change_id    = 0;
 572 	e_table->expansion_change_id    = 0;
 573 	e_table->dimension_change_id    = 0;
 574 	e_table->reflow_idle_id         = 0;
 575 	e_table->scroll_idle_id         = 0;
 576 
 577 	e_table->alternating_row_colors = 1;
 578 	e_table->horizontal_draw_grid   = 1;
 579 	e_table->vertical_draw_grid     = 1;
 580 	e_table->draw_focus             = 1;
 581 	e_table->cursor_mode            = E_CURSOR_SIMPLE;
 582 	e_table->length_threshold       = 200;
 583 	e_table->uniform_row_height     = FALSE;
 584 
 585 	e_table->need_rebuild           = 0;
 586 	e_table->rebuild_idle_id        = 0;
 587 
 588 	e_table->horizontal_scrolling   = FALSE;
 589 	e_table->horizontal_resize      = FALSE;
 590 
 591 	e_table->click_to_add_message   = NULL;
 592 	e_table->domain                 = NULL;
 593 
 594 	e_table->drop_row               = -1;
 595 	e_table->drop_col               = -1;
 596 	e_table->site                   = NULL;
 597 
 598 	e_table->do_drag                = 0;
 599 
 600 	e_table->sorter                 = NULL;
 601 	e_table->selection              = e_table_selection_model_new ();
 602 	e_table->cursor_loc             = E_TABLE_CURSOR_LOC_NONE;
 603 	e_table->spec                   = NULL;
 604 
 605 	e_table->always_search          = g_getenv ("GAL_ALWAYS_SEARCH") ? TRUE : FALSE;
 606 
 607 	e_table->search                 = NULL;
 608 	e_table->search_search_id       = 0;
 609 	e_table->search_accept_id       = 0;
 610 
 611 	e_table->current_search_col     = NULL;
 612 
 613 	e_table->header_width           = 0;
 614 
 615 	e_table->state_changed		= FALSE;
 616 	e_table->state_change_freeze	= 0;
 617 }
 618 
 619 /* Grab_focus handler for the ETable */
 620 static void
 621 et_grab_focus (GtkWidget *widget)
 622 {
 623 	ETable *e_table;
 624 
 625 	e_table = E_TABLE (widget);
 626 
 627 	gtk_widget_grab_focus (GTK_WIDGET (e_table->table_canvas));
 628 }
 629 
 630 /* Focus handler for the ETable */
 631 static gint
 632 et_focus (GtkWidget *container,
 633           GtkDirectionType direction)
 634 {
 635 	ETable *e_table;
 636 
 637 	e_table = E_TABLE (container);
 638 
 639 	if (gtk_container_get_focus_child (GTK_CONTAINER (container))) {
 640 		gtk_container_set_focus_child (GTK_CONTAINER (container), NULL);
 641 		return FALSE;
 642 	}
 643 
 644 	return gtk_widget_child_focus (GTK_WIDGET (e_table->table_canvas), direction);
 645 }
 646 
 647 static void
 648 set_header_canvas_width (ETable *e_table)
 649 {
 650 	gdouble oldwidth, oldheight, width;
 651 
 652 	if (!(e_table->header_item && e_table->header_canvas && e_table->table_canvas))
 653 		return;
 654 
 655 	gnome_canvas_get_scroll_region (
 656 		GNOME_CANVAS (e_table->table_canvas),
 657 		NULL, NULL, &width, NULL);
 658 	gnome_canvas_get_scroll_region (
 659 		GNOME_CANVAS (e_table->header_canvas),
 660 		NULL, NULL, &oldwidth, &oldheight);
 661 
 662 	if (oldwidth != width ||
 663 	    oldheight != E_TABLE_HEADER_ITEM (e_table->header_item)->height - 1)
 664 		gnome_canvas_set_scroll_region (
 665 			GNOME_CANVAS (e_table->header_canvas),
 666 			0, 0, width, /*  COLUMN_HEADER_HEIGHT - 1 */
 667 			E_TABLE_HEADER_ITEM (e_table->header_item)->height - 1);
 668 
 669 }
 670 
 671 static void
 672 header_canvas_size_allocate (GtkWidget *widget,
 673                              GtkAllocation *alloc,
 674                              ETable *e_table)
 675 {
 676 	GtkAllocation allocation;
 677 
 678 	set_header_canvas_width (e_table);
 679 
 680 	gtk_widget_get_allocation (
 681 		GTK_WIDGET (e_table->header_canvas), &allocation);
 682 
 683 	/* When the header item is created ->height == 0,
 684 	 * as the font is only created when everything is realized.
 685 	 * So we set the usize here as well, so that the size of the
 686 	 * header is correct */
 687 	if (allocation.height != E_TABLE_HEADER_ITEM (e_table->header_item)->height)
 688 		g_object_set (
 689 			e_table->header_canvas, "height-request",
 690 			E_TABLE_HEADER_ITEM (e_table->header_item)->height,
 691 			NULL);
 692 }
 693 
 694 static void
 695 group_info_changed (ETableSortInfo *info,
 696                     ETable *et)
 697 {
 698 	gboolean will_be_grouped = e_table_sort_info_grouping_get_count (info) > 0;
 699 	clear_current_search_col (et);
 700 	if (et->is_grouped || will_be_grouped) {
 701 		et->need_rebuild = TRUE;
 702 		if (!et->rebuild_idle_id) {
 703 			g_object_run_dispose (G_OBJECT (et->group));
 704 			et->group = NULL;
 705 			et->rebuild_idle_id = g_idle_add_full (20, changed_idle, et, NULL);
 706 		}
 707 	}
 708 	e_table_state_change (et);
 709 }
 710 
 711 static void
 712 sort_info_changed (ETableSortInfo *info,
 713                    ETable *et)
 714 {
 715 	clear_current_search_col (et);
 716 	e_table_state_change (et);
 717 }
 718 
 719 static void
 720 e_table_setup_header (ETable *e_table)
 721 {
 722 	gchar *pointer;
 723 	e_table->header_canvas = GNOME_CANVAS (e_canvas_new ());
 724 
 725 	gtk_widget_show (GTK_WIDGET (e_table->header_canvas));
 726 
 727 	pointer = g_strdup_printf ("%p", (gpointer) e_table);
 728 
 729 	e_table->header_item = gnome_canvas_item_new (
 730 		gnome_canvas_root (e_table->header_canvas),
 731 		e_table_header_item_get_type (),
 732 		"ETableHeader", e_table->header,
 733 		"full_header", e_table->full_header,
 734 		"sort_info", e_table->sort_info,
 735 		"dnd_code", pointer,
 736 		"table", e_table,
 737 		NULL);
 738 
 739 	g_free (pointer);
 740 
 741 	g_signal_connect (
 742 		e_table->header_canvas, "size_allocate",
 743 		G_CALLBACK (header_canvas_size_allocate), e_table);
 744 
 745 	g_object_set (
 746 		e_table->header_canvas, "height-request",
 747 		E_TABLE_HEADER_ITEM (e_table->header_item)->height, NULL);
 748 }
 749 
 750 static gboolean
 751 table_canvas_reflow_idle (ETable *e_table)
 752 {
 753 	gdouble height, width;
 754 	gdouble oldheight, oldwidth;
 755 	GtkAllocation allocation;
 756 
 757 	gtk_widget_get_allocation (
 758 		GTK_WIDGET (e_table->table_canvas), &allocation);
 759 
 760 	g_object_get (
 761 		e_table->canvas_vbox,
 762 		"height", &height, "width", &width, NULL);
 763 	height = MAX ((gint) height, allocation.height);
 764 	width = MAX ((gint) width, allocation.width);
 765 	/* I have no idea why this needs to be -1, but it works. */
 766 	gnome_canvas_get_scroll_region (
 767 		GNOME_CANVAS (e_table->table_canvas),
 768 		NULL, NULL, &oldwidth, &oldheight);
 769 
 770 	if (oldwidth != width - 1 ||
 771 	    oldheight != height - 1) {
 772 		gnome_canvas_set_scroll_region (
 773 			GNOME_CANVAS (e_table->table_canvas),
 774 			0, 0, width - 1, height - 1);
 775 		set_header_canvas_width (e_table);
 776 	}
 777 	e_table->reflow_idle_id = 0;
 778 	return FALSE;
 779 }
 780 
 781 static void
 782 table_canvas_size_allocate (GtkWidget *widget,
 783                             GtkAllocation *alloc,
 784                             ETable *e_table)
 785 {
 786 	gdouble width;
 787 	gdouble height;
 788 	GValue *val = g_new0 (GValue, 1);
 789 	g_value_init (val, G_TYPE_DOUBLE);
 790 
 791 	width = alloc->width;
 792 	g_value_set_double (val, width);
 793 	g_object_get (
 794 		e_table->canvas_vbox,
 795 		"height", &height,
 796 		NULL);
 797 	height = MAX ((gint) height, alloc->height);
 798 
 799 	g_object_set (
 800 		e_table->canvas_vbox,
 801 		"width", width,
 802 		NULL);
 803 	g_object_set_property (G_OBJECT (e_table->header), "width", val);
 804 	g_free (val);
 805 	if (e_table->reflow_idle_id)
 806 		g_source_remove (e_table->reflow_idle_id);
 807 	table_canvas_reflow_idle (e_table);
 808 
 809 	e_table->size_allocated = TRUE;
 810 
 811 	if (e_table->need_rebuild && !e_table->rebuild_idle_id)
 812 		e_table->rebuild_idle_id = g_idle_add_full (20, changed_idle, e_table, NULL);
 813 }
 814 
 815 static void
 816 table_canvas_reflow (GnomeCanvas *canvas,
 817                      ETable *e_table)
 818 {
 819 	if (!e_table->reflow_idle_id)
 820 		e_table->reflow_idle_id = g_idle_add_full (
 821 			400, (GSourceFunc) table_canvas_reflow_idle,
 822 			e_table, NULL);
 823 }
 824 
 825 static void
 826 click_to_add_cursor_change (ETableClickToAdd *etcta,
 827                             gint row,
 828                             gint col,
 829                             ETable *et)
 830 {
 831 	if (et->cursor_loc == E_TABLE_CURSOR_LOC_TABLE) {
 832 		e_selection_model_clear (E_SELECTION_MODEL (et->selection));
 833 	}
 834 	et->cursor_loc = E_TABLE_CURSOR_LOC_ETCTA;
 835 }
 836 
 837 static void
 838 group_cursor_change (ETableGroup *etg,
 839                      gint row,
 840                      ETable *et)
 841 {
 842 	ETableCursorLoc old_cursor_loc;
 843 
 844 	old_cursor_loc = et->cursor_loc;
 845 
 846 	et->cursor_loc = E_TABLE_CURSOR_LOC_TABLE;
 847 	g_signal_emit (et, et_signals[CURSOR_CHANGE], 0, row);
 848 
 849 	if (old_cursor_loc == E_TABLE_CURSOR_LOC_ETCTA && et->click_to_add)
 850 		e_table_click_to_add_commit (E_TABLE_CLICK_TO_ADD (et->click_to_add));
 851 }
 852 
 853 static void
 854 group_cursor_activated (ETableGroup *etg,
 855                         gint row,
 856                         ETable *et)
 857 {
 858 	g_signal_emit (et, et_signals[CURSOR_ACTIVATED], 0, row);
 859 }
 860 
 861 static void
 862 group_double_click (ETableGroup *etg,
 863                     gint row,
 864                     gint col,
 865                     GdkEvent *event,
 866                     ETable *et)
 867 {
 868 	g_signal_emit (et, et_signals[DOUBLE_CLICK], 0, row, col, event);
 869 }
 870 
 871 static gboolean
 872 group_right_click (ETableGroup *etg,
 873                    gint row,
 874                    gint col,
 875                    GdkEvent *event,
 876                    ETable *et)
 877 {
 878 	gboolean return_val = FALSE;
 879 
 880 	g_signal_emit (
 881 		et, et_signals[RIGHT_CLICK], 0,
 882 		row, col, event, &return_val);
 883 
 884 	return return_val;
 885 }
 886 
 887 static gboolean
 888 group_click (ETableGroup *etg,
 889              gint row,
 890              gint col,
 891              GdkEvent *event,
 892              ETable *et)
 893 {
 894 	gboolean return_val = 0;
 895 
 896 	g_signal_emit (
 897 		et, et_signals[CLICK], 0,
 898 		row, col, event, &return_val);
 899 
 900 	return return_val;
 901 }
 902 
 903 static gboolean
 904 group_key_press (ETableGroup *etg,
 905                  gint row,
 906                  gint col,
 907                  GdkEvent *event,
 908                  ETable *et)
 909 {
 910 	gboolean return_val = FALSE;
 911 	GdkEventKey *key = (GdkEventKey *) event;
 912 	gint y, row_local, col_local;
 913 	GtkAdjustment *adjustment;
 914 	GtkScrollable *scrollable;
 915 	gdouble page_size;
 916 	gdouble upper;
 917 	gdouble value;
 918 
 919 	scrollable = GTK_SCROLLABLE (et->table_canvas);
 920 	adjustment = gtk_scrollable_get_vadjustment (scrollable);
 921 
 922 	switch (key->keyval) {
 923 	case GDK_KEY_Page_Down:
 924 	case GDK_KEY_KP_Page_Down:
 925 		page_size = gtk_adjustment_get_page_size (adjustment);
 926 		upper = gtk_adjustment_get_value (adjustment);
 927 		value = gtk_adjustment_get_value (adjustment);
 928 
 929 		y = CLAMP (value + (2 * page_size - 50), 0, upper);
 930 		y -= value;
 931 		e_table_get_cell_at (et, 30, y, &row_local, &col_local);
 932 
 933 		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)

934 row_local = e_table_model_row_count (et->model) - 1; 935 936 row_local = e_table_view_to_model_row (et, row_local); 937 col_local = e_selection_model_cursor_col (E_SELECTION_MODEL (et->selection)); 938 e_selection_model_select_as_key_press ( 939 E_SELECTION_MODEL (et->selection), 940 row_local, col_local, key->state); 941 return_val = 1; 942 break; 943 case GDK_KEY_Page_Up: 944 case GDK_KEY_KP_Page_Up: 945 page_size = gtk_adjustment_get_page_size (adjustment); 946 upper = gtk_adjustment_get_upper (adjustment); 947 value = gtk_adjustment_get_value (adjustment); 948 949 y = CLAMP (value - (page_size - 50), 0, upper); 950 y -= value; 951 e_table_get_cell_at (et, 30, y, &row_local, &col_local); 952 953 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)

954 row_local = 0; 955 956 row_local = e_table_view_to_model_row (et, row_local); 957 col_local = e_selection_model_cursor_col (E_SELECTION_MODEL (et->selection)); 958 e_selection_model_select_as_key_press ( 959 E_SELECTION_MODEL (et->selection), 960 row_local, col_local, key->state); 961 return_val = 1; 962 break; 963 case GDK_KEY_BackSpace: 964 init_search (et); 965 if (e_table_search_backspace (et->search)) 966 return TRUE; 967 /* Fall through */ 968 default: 969 init_search (et); 970 if ((key->state & ~(GDK_SHIFT_MASK | GDK_LOCK_MASK | 971 GDK_MOD1_MASK | GDK_MOD2_MASK | GDK_MOD3_MASK | 972 GDK_MOD4_MASK | GDK_MOD5_MASK)) == 0 973 && ((key->keyval >= GDK_KEY_a && key->keyval <= GDK_KEY_z) || 974 (key->keyval >= GDK_KEY_A && key->keyval <= GDK_KEY_Z) || 975 (key->keyval >= GDK_KEY_0 && key->keyval <= GDK_KEY_9))) 976 e_table_search_input_character (et->search, key->keyval); 977 g_signal_emit ( 978 et, et_signals[KEY_PRESS], 0, 979 row, col, event, &return_val); 980 break; 981 } 982 return return_val; 983 } 984 985 static gboolean 986 group_start_drag (ETableGroup *etg, 987 gint row, 988 gint col, 989 GdkEvent *event, 990 ETable *et) 991 { 992 gboolean return_val = TRUE; 993 994 g_signal_emit ( 995 et, et_signals[START_DRAG], 0, 996 row, col, event, &return_val); 997 998 return return_val; 999 } 1000 1001 static void 1002 et_table_model_changed (ETableModel *model, 1003 ETable *et) 1004 { 1005 et->need_rebuild = TRUE; 1006 if (!et->rebuild_idle_id) { 1007 g_object_run_dispose (G_OBJECT (et->group)); 1008 et->group = NULL; 1009 et->rebuild_idle_id = g_idle_add_full (20, changed_idle, et, NULL); 1010 } 1011 } 1012 1013 static void 1014 et_table_row_changed (ETableModel *table_model, 1015 gint row, 1016 ETable *et) 1017 { 1018 if (!et->need_rebuild) { 1019 if (e_table_group_remove (et->group, row)) 1020 e_table_group_add (et->group, row); 1021 CHECK_HORIZONTAL (et); 1022 } 1023 } 1024 1025 static void 1026 et_table_cell_changed (ETableModel *table_model, 1027 gint view_col, 1028 gint row, 1029 ETable *et) 1030 { 1031 et_table_row_changed (table_model, row, et); 1032 } 1033 1034 static void 1035 et_table_rows_inserted (ETableModel *table_model, 1036 gint row, 1037 gint count, 1038 ETable *et) 1039 { 1040 /* This number has already been decremented. */ 1041 gint row_count = e_table_model_row_count (table_model); 1042 if (!et->need_rebuild) { 1043 gint i; 1044 if (row != row_count - count) 1045 e_table_group_increment (et->group, row, count); 1046 for (i = 0; i < count; i++) 1047 e_table_group_add (et->group, row + i); 1048 CHECK_HORIZONTAL (et); 1049 } 1050 } 1051 1052 static void 1053 et_table_rows_deleted (ETableModel *table_model, 1054 gint row, 1055 gint count, 1056 ETable *et) 1057 { 1058 gint row_count = e_table_model_row_count (table_model); 1059 if (!et->need_rebuild) { 1060 gint i; 1061 for (i = 0; i < count; i++) 1062 e_table_group_remove (et->group, row + i); 1063 if (row != row_count) 1064 e_table_group_decrement (et->group, row, count); 1065 CHECK_HORIZONTAL (et); 1066 } 1067 } 1068 1069 static void 1070 et_build_groups (ETable *et) 1071 { 1072 gboolean was_grouped = et->is_grouped; 1073 1074 et->is_grouped = e_table_sort_info_grouping_get_count (et->sort_info) > 0; 1075 1076 et->group = e_table_group_new ( 1077 GNOME_CANVAS_GROUP (et->canvas_vbox), 1078 et->full_header, 1079 et->header, 1080 et->model, 1081 et->sort_info, 1082 0); 1083 1084 if (et->use_click_to_add_end) 1085 e_canvas_vbox_add_item_start ( 1086 E_CANVAS_VBOX (et->canvas_vbox), 1087 GNOME_CANVAS_ITEM (et->group)); 1088 else 1089 e_canvas_vbox_add_item ( 1090 E_CANVAS_VBOX (et->canvas_vbox), 1091 GNOME_CANVAS_ITEM (et->group)); 1092 1093 gnome_canvas_item_set ( 1094 GNOME_CANVAS_ITEM (et->group), 1095 "alternating_row_colors", et->alternating_row_colors, 1096 "horizontal_draw_grid", et->horizontal_draw_grid, 1097 "vertical_draw_grid", et->vertical_draw_grid, 1098 "drawfocus", et->draw_focus, 1099 "cursor_mode", et->cursor_mode, 1100 "length_threshold", et->length_threshold, 1101 "uniform_row_height", et->uniform_row_height, 1102 "selection_model", et->selection, 1103 NULL); 1104 1105 g_signal_connect ( 1106 et->group, "cursor_change", 1107 G_CALLBACK (group_cursor_change), et); 1108 g_signal_connect ( 1109 et->group, "cursor_activated", 1110 G_CALLBACK (group_cursor_activated), et); 1111 g_signal_connect ( 1112 et->group, "double_click", 1113 G_CALLBACK (group_double_click), et); 1114 g_signal_connect ( 1115 et->group, "right_click", 1116 G_CALLBACK (group_right_click), et); 1117 g_signal_connect ( 1118 et->group, "click", 1119 G_CALLBACK (group_click), et); 1120 g_signal_connect ( 1121 et->group, "key_press", 1122 G_CALLBACK (group_key_press), et); 1123 g_signal_connect ( 1124 et->group, "start_drag", 1125 G_CALLBACK (group_start_drag), et); 1126 1127 if (!(et->is_grouped) && was_grouped) 1128 et_disconnect_model (et); 1129 1130 if (et->is_grouped && (!was_grouped)) { 1131 et->table_model_change_id = g_signal_connect ( 1132 et->model, "model_changed", 1133 G_CALLBACK (et_table_model_changed), et); 1134 1135 et->table_row_change_id = g_signal_connect ( 1136 et->model, "model_row_changed", 1137 G_CALLBACK (et_table_row_changed), et); 1138 1139 et->table_cell_change_id = g_signal_connect ( 1140 et->model, "model_cell_changed", 1141 G_CALLBACK (et_table_cell_changed), et); 1142 1143 et->table_rows_inserted_id = g_signal_connect ( 1144 et->model, "model_rows_inserted", 1145 G_CALLBACK (et_table_rows_inserted), et); 1146 1147 et->table_rows_deleted_id = g_signal_connect ( 1148 et->model, "model_rows_deleted", 1149 G_CALLBACK (et_table_rows_deleted), et); 1150 1151 } 1152 1153 if (et->is_grouped) 1154 e_table_fill_table (et, et->model); 1155 } 1156 1157 static gboolean 1158 changed_idle (gpointer data) 1159 { 1160 ETable *et = E_TABLE (data); 1161 1162 /* Wait until we have a valid size allocation. */ 1163 if (et->need_rebuild && et->size_allocated) { 1164 GtkWidget *widget; 1165 GtkAllocation allocation; 1166 1167 if (et->group) 1168 g_object_run_dispose (G_OBJECT (et->group)); 1169 et_build_groups (et); 1170 1171 widget = GTK_WIDGET (et->table_canvas); 1172 gtk_widget_get_allocation (widget, &allocation); 1173 1174 g_object_set ( 1175 et->canvas_vbox, 1176 "width", (gdouble) allocation.width, 1177 NULL); 1178 1179 table_canvas_size_allocate (widget, &allocation, et); 1180 1181 et->need_rebuild = 0; 1182 } 1183 1184 et->rebuild_idle_id = 0; 1185 1186 CHECK_HORIZONTAL (et); 1187 1188 return FALSE; 1189 } 1190 1191 static void 1192 et_canvas_realize (GtkWidget *canvas, 1193 ETable *e_table) 1194 { 1195 GtkWidget *widget; 1196 GtkStyle *style; 1197 1198 widget = GTK_WIDGET (e_table->table_canvas); 1199 style = gtk_widget_get_style (widget); 1200 1201 gnome_canvas_item_set ( 1202 e_table->white_item, 1203 "fill_color_gdk", &style->base[GTK_STATE_NORMAL], 1204 NULL); 1205 1206 CHECK_HORIZONTAL (e_table); 1207 set_header_width (e_table); 1208 } 1209 1210 static gboolean 1211 white_item_event (GnomeCanvasItem *white_item, 1212 GdkEvent *event, 1213 ETable *e_table) 1214 { 1215 gboolean return_val = 0; 1216 1217 g_signal_emit ( 1218 e_table, et_signals[WHITE_SPACE_EVENT], 0, 1219 event, &return_val); 1220 1221 return return_val; 1222 } 1223 1224 static void 1225 et_eti_leave_edit (ETable *et) 1226 { 1227 GnomeCanvas *canvas = et->table_canvas; 1228 1229 if (gtk_widget_has_focus (GTK_WIDGET (canvas))) { 1230 GnomeCanvasItem *item = GNOME_CANVAS (canvas)->focused_item; 1231 1232 if (E_IS_TABLE_ITEM (item)) { 1233 e_table_item_leave_edit_(E_TABLE_ITEM (item)); 1234 } 1235 } 1236 } 1237 1238 static gint 1239 et_canvas_root_event (GnomeCanvasItem *root, 1240 GdkEvent *event, 1241 ETable *e_table) 1242 { 1243 switch (event->type) { 1244 case GDK_BUTTON_PRESS: 1245 case GDK_2BUTTON_PRESS: 1246 case GDK_BUTTON_RELEASE: 1247 if (event->button.button != 4 && event->button.button != 5) { 1248 et_eti_leave_edit (e_table); 1249 return TRUE; 1250 } 1251 break; 1252 default: 1253 break; 1254 } 1255 1256 return FALSE; 1257 } 1258 1259 /* Finds the first descendant of the group that is an ETableItem and focuses it */ 1260 static void 1261 focus_first_etable_item (ETableGroup *group) 1262 { 1263 GnomeCanvasGroup *cgroup; 1264 GList *l; 1265 1266 cgroup = GNOME_CANVAS_GROUP (group); 1267 1268 for (l = cgroup->item_list; l; l = l->next) { 1269 GnomeCanvasItem *i; 1270 1271 i = GNOME_CANVAS_ITEM (l->data); 1272 1273 if (E_IS_TABLE_GROUP (i)) 1274 focus_first_etable_item (E_TABLE_GROUP (i)); 1275 else if (E_IS_TABLE_ITEM (i)) { 1276 e_table_item_set_cursor (E_TABLE_ITEM (i), 0, 0); 1277 gnome_canvas_item_grab_focus (i); 1278 } 1279 } 1280 } 1281 1282 /* Handler for focus events in the table_canvas; we have to repaint ourselves 1283 * always, and also give the focus to some ETableItem if we get focused. 1284 */ 1285 static gint 1286 table_canvas_focus_event_cb (GtkWidget *widget, 1287 GdkEventFocus *event, 1288 gpointer data) 1289 { 1290 GnomeCanvas *canvas; 1291 ECanvas *ecanvas; 1292 ETable *etable; 1293 1294 gtk_widget_queue_draw (widget); 1295 canvas = GNOME_CANVAS (widget); 1296 ecanvas = E_CANVAS (widget); 1297 1298 if (!event->in) { 1299 gtk_im_context_focus_out (ecanvas->im_context); 1300 return FALSE; 1301 } else { 1302 gtk_im_context_focus_in (ecanvas->im_context); 1303 } 1304 1305 etable = E_TABLE (data); 1306 1307 if (e_table_model_row_count (etable->model) < 1 1308 && (etable->click_to_add) 1309 && !(E_TABLE_CLICK_TO_ADD (etable->click_to_add)->row)) { 1310 gnome_canvas_item_grab_focus (etable->canvas_vbox); 1311 gnome_canvas_item_grab_focus (etable->click_to_add); 1312 } else if (!canvas->focused_item && etable->group) { 1313 focus_first_etable_item (etable->group); 1314 } else if (canvas->focused_item) { 1315 ESelectionModel *selection = (ESelectionModel *) etable->selection; 1316 1317 /* check whether click_to_add already got the focus */ 1318 if (etable->click_to_add) { 1319 GnomeCanvasItem *row = E_TABLE_CLICK_TO_ADD (etable->click_to_add)->row; 1320 if (canvas->focused_item == row) 1321 return TRUE; 1322 } 1323 1324 if (e_selection_model_cursor_row (selection) == -1) 1325 focus_first_etable_item (etable->group); 1326 } 1327 1328 return FALSE; 1329 } 1330 1331 static gboolean 1332 canvas_vbox_event (ECanvasVbox *vbox, 1333 GdkEventKey *key, 1334 ETable *etable) 1335 { 1336 if (key->type != GDK_KEY_PRESS && 1337 key->type != GDK_KEY_RELEASE) { 1338 return FALSE; 1339 } 1340 switch (key->keyval) { 1341 case GDK_KEY_Tab: 1342 case GDK_KEY_KP_Tab: 1343 case GDK_KEY_ISO_Left_Tab: 1344 if ((key->state & GDK_CONTROL_MASK) && etable->click_to_add) { 1345 gnome_canvas_item_grab_focus (etable->click_to_add); 1346 break; 1347 } 1348 default: 1349 return FALSE; 1350 } 1351 1352 return TRUE; 1353 } 1354 1355 static gboolean 1356 click_to_add_event (ETableClickToAdd *etcta, 1357 GdkEventKey *key, 1358 ETable *etable) 1359 { 1360 if (key->type != GDK_KEY_PRESS && 1361 key->type != GDK_KEY_RELEASE) { 1362 return FALSE; 1363 } 1364 switch (key->keyval) { 1365 case GDK_KEY_Tab: 1366 case GDK_KEY_KP_Tab: 1367 case GDK_KEY_ISO_Left_Tab: 1368 if (key->state & GDK_CONTROL_MASK) { 1369 if (etable->group) { 1370 if (e_table_model_row_count (etable->model) > 0) 1371 focus_first_etable_item (etable->group); 1372 else 1373 gtk_widget_child_focus ( 1374 gtk_widget_get_toplevel ( 1375 GTK_WIDGET (etable->table_canvas)), 1376 GTK_DIR_TAB_FORWARD); 1377 break; 1378 } 1379 } 1380 default: 1381 return FALSE; 1382 } 1383 1384 return FALSE; 1385 } 1386 1387 static void 1388 e_table_setup_table (ETable *e_table, 1389 ETableHeader *full_header, 1390 ETableHeader *header, 1391 ETableModel *model) 1392 { 1393 GtkWidget *widget; 1394 GtkStyle *style; 1395 1396 e_table->table_canvas = GNOME_CANVAS (e_canvas_new ()); 1397 g_signal_connect ( 1398 e_table->table_canvas, "size_allocate", 1399 G_CALLBACK (table_canvas_size_allocate), e_table); 1400 g_signal_connect ( 1401 e_table->table_canvas, "focus_in_event", 1402 G_CALLBACK (table_canvas_focus_event_cb), e_table); 1403 g_signal_connect ( 1404 e_table->table_canvas, "focus_out_event", 1405 G_CALLBACK (table_canvas_focus_event_cb), e_table); 1406 1407 g_signal_connect ( 1408 e_table, "drag_begin", 1409 G_CALLBACK (et_drag_begin), e_table); 1410 g_signal_connect ( 1411 e_table, "drag_end", 1412 G_CALLBACK (et_drag_end), e_table); 1413 g_signal_connect ( 1414 e_table, "drag_data_get", 1415 G_CALLBACK (et_drag_data_get), e_table); 1416 g_signal_connect ( 1417 e_table, "drag_data_delete", 1418 G_CALLBACK (et_drag_data_delete), e_table); 1419 g_signal_connect ( 1420 e_table, "drag_motion", 1421 G_CALLBACK (et_drag_motion), e_table); 1422 g_signal_connect ( 1423 e_table, "drag_leave", 1424 G_CALLBACK (et_drag_leave), e_table); 1425 g_signal_connect ( 1426 e_table, "drag_drop", 1427 G_CALLBACK (et_drag_drop), e_table); 1428 g_signal_connect ( 1429 e_table, "drag_data_received", 1430 G_CALLBACK (et_drag_data_received), e_table); 1431 1432 g_signal_connect ( 1433 e_table->table_canvas, "reflow", 1434 G_CALLBACK (table_canvas_reflow), e_table); 1435 1436 widget = GTK_WIDGET (e_table->table_canvas); 1437 style = gtk_widget_get_style (widget); 1438 1439 gtk_widget_show (widget); 1440 1441 e_table->white_item = gnome_canvas_item_new ( 1442 gnome_canvas_root (e_table->table_canvas), 1443 e_canvas_background_get_type (), 1444 "fill_color_gdk", &style->base[GTK_STATE_NORMAL], 1445 NULL); 1446 1447 g_signal_connect ( 1448 e_table->white_item, "event", 1449 G_CALLBACK (white_item_event), e_table); 1450 1451 g_signal_connect ( 1452 e_table->table_canvas, "realize", 1453 G_CALLBACK (et_canvas_realize), e_table); 1454 1455 g_signal_connect ( 1456 gnome_canvas_root (e_table->table_canvas), "event", 1457 G_CALLBACK (et_canvas_root_event), e_table); 1458 1459 e_table->canvas_vbox = gnome_canvas_item_new ( 1460 gnome_canvas_root (e_table->table_canvas), 1461 e_canvas_vbox_get_type (), 1462 "spacing", 10.0, 1463 NULL); 1464 1465 g_signal_connect ( 1466 e_table->canvas_vbox, "event", 1467 G_CALLBACK (canvas_vbox_event), e_table); 1468 1469 et_build_groups (e_table); 1470 1471 if (e_table->use_click_to_add) { 1472 e_table->click_to_add = gnome_canvas_item_new ( 1473 GNOME_CANVAS_GROUP (e_table->canvas_vbox), 1474 e_table_click_to_add_get_type (), 1475 "header", e_table->header, 1476 "model", e_table->model, 1477 "message", e_table->click_to_add_message, 1478 NULL); 1479 1480 if (e_table->use_click_to_add_end) 1481 e_canvas_vbox_add_item ( 1482 E_CANVAS_VBOX (e_table->canvas_vbox), 1483 e_table->click_to_add); 1484 else 1485 e_canvas_vbox_add_item_start ( 1486 E_CANVAS_VBOX (e_table->canvas_vbox), 1487 e_table->click_to_add); 1488 1489 g_signal_connect ( 1490 e_table->click_to_add, "event", 1491 G_CALLBACK (click_to_add_event), e_table); 1492 g_signal_connect ( 1493 e_table->click_to_add, "cursor_change", 1494 G_CALLBACK (click_to_add_cursor_change), e_table); 1495 } 1496 } 1497 1498 static void 1499 e_table_fill_table (ETable *e_table, 1500 ETableModel *model) 1501 { 1502 e_table_group_add_all (e_table->group); 1503 } 1504 1505 /** 1506 * e_table_set_state_object: 1507 * @e_table: The #ETable object to modify 1508 * @state: The #ETableState to use 1509 * 1510 * This routine sets the state of the #ETable from the given 1511 * #ETableState. 1512 * 1513 **/ 1514 void 1515 e_table_set_state_object (ETable *e_table, 1516 ETableState *state) 1517 { 1518 GValue *val; 1519 GtkWidget *widget; 1520 GtkAllocation allocation; 1521 1522 val = g_new0 (GValue, 1); 1523 g_value_init (val, G_TYPE_DOUBLE); 1524 1525 connect_header (e_table, state); 1526 1527 widget = GTK_WIDGET (e_table->table_canvas); 1528 gtk_widget_get_allocation (widget, &allocation); 1529 1530 g_value_set_double (val, (gdouble) allocation.width); 1531 g_object_set_property (G_OBJECT (e_table->header), "width", val); 1532 g_free (val); 1533 1534 if (e_table->sort_info) { 1535 if (e_table->group_info_change_id) 1536 g_signal_handler_disconnect ( 1537 e_table->sort_info, 1538 e_table->group_info_change_id); 1539 if (e_table->sort_info_change_id) 1540 g_signal_handler_disconnect ( 1541 e_table->sort_info, 1542 e_table->sort_info_change_id); 1543 g_object_unref (e_table->sort_info); 1544 } 1545 if (state->sort_info) { 1546 e_table->sort_info = e_table_sort_info_duplicate (state->sort_info); 1547 e_table_sort_info_set_can_group ( 1548 e_table->sort_info, e_table->allow_grouping); 1549 e_table->group_info_change_id = g_signal_connect ( 1550 e_table->sort_info, "group_info_changed", 1551 G_CALLBACK (group_info_changed), e_table); 1552 1553 e_table->sort_info_change_id = g_signal_connect ( 1554 e_table->sort_info, "sort_info_changed", 1555 G_CALLBACK (sort_info_changed), e_table); 1556 } 1557 else 1558 e_table->sort_info = NULL; 1559 1560 if (e_table->sorter) 1561 g_object_set ( 1562 e_table->sorter, 1563 "sort_info", e_table->sort_info, 1564 NULL); 1565 if (e_table->header_item) 1566 g_object_set ( 1567 e_table->header_item, 1568 "ETableHeader", e_table->header, 1569 "sort_info", e_table->sort_info, 1570 NULL); 1571 if (e_table->click_to_add) 1572 g_object_set ( 1573 e_table->click_to_add, 1574 "header", e_table->header, 1575 NULL); 1576 1577 e_table->need_rebuild = TRUE; 1578 if (!e_table->rebuild_idle_id) 1579 e_table->rebuild_idle_id = g_idle_add_full (20, changed_idle, e_table, NULL); 1580 1581 e_table_state_change (e_table); 1582 } 1583 1584 /** 1585 * e_table_set_state: 1586 * @e_table: The #ETable object to modify 1587 * @state_str: a string representing an #ETableState 1588 * 1589 * This routine sets the state of the #ETable from a string. 1590 * 1591 **/ 1592 void 1593 e_table_set_state (ETable *e_table, 1594 const gchar *state_str) 1595 { 1596 ETableState *state; 1597 1598 g_return_if_fail (E_IS_TABLE (e_table)); 1599 g_return_if_fail (state_str != NULL); 1600 1601 state = e_table_state_new (); 1602 e_table_state_load_from_string (state, state_str); 1603 1604 if (state->col_count > 0) 1605 e_table_set_state_object (e_table, state); 1606 1607 g_object_unref (state); 1608 } 1609 1610 /** 1611 * e_table_load_state: 1612 * @e_table: The #ETable object to modify 1613 * @filename: name of the file to use 1614 * 1615 * This routine sets the state of the #ETable from a file. 1616 * 1617 **/ 1618 void 1619 e_table_load_state (ETable *e_table, 1620 const gchar *filename) 1621 { 1622 ETableState *state; 1623 1624 g_return_if_fail (E_IS_TABLE (e_table)); 1625 g_return_if_fail (filename != NULL); 1626 1627 state = e_table_state_new (); 1628 e_table_state_load_from_file (state, filename); 1629 1630 if (state->col_count > 0) 1631 e_table_set_state_object (e_table, state); 1632 1633 g_object_unref (state); 1634 } 1635 1636 /** 1637 * e_table_get_state_object: 1638 * @e_table: #ETable object to act on 1639 * 1640 * Builds an #ETableState corresponding to the current state of the 1641 * #ETable. 1642 * 1643 * Return value: 1644 * The %ETableState object generated. 1645 **/ 1646 ETableState * 1647 e_table_get_state_object (ETable *e_table) 1648 { 1649 ETableState *state; 1650 gint full_col_count; 1651 gint i, j; 1652 1653 state = e_table_state_new (); 1654 if (state->sort_info) 1655 g_object_unref (state->sort_info); 1656 state->sort_info = e_table->sort_info; 1657 g_object_ref (state->sort_info); 1658 1659 state->col_count = e_table_header_count (e_table->header); 1660 full_col_count = e_table_header_count (e_table->full_header); 1661 state->columns = g_new (int, state->col_count); 1662 state->expansions = g_new (double, state->col_count); 1663 for (i = 0; i < state->col_count; i++) { 1664 ETableCol *col = e_table_header_get_column (e_table->header, i); 1665 state->columns[i] = -1; 1666 for (j = 0; j < full_col_count; j++) { 1667 if (col->col_idx == e_table_header_index (e_table->full_header, j)) { 1668 state->columns[i] = j; 1669 break; 1670 } 1671 } 1672 state->expansions[i] = col->expansion; 1673 } 1674 1675 return state; 1676 } 1677 1678 /** 1679 * e_table_get_state: 1680 * @e_table: The #ETable to act on. 1681 * 1682 * Builds a state object based on the current state and returns the 1683 * string corresponding to that state. 1684 * 1685 * Return value: 1686 * A string describing the current state of the #ETable. 1687 **/ 1688 gchar *e_table_get_state (ETable *e_table) 1689 { 1690 ETableState *state; 1691 gchar *string; 1692 1693 state = e_table_get_state_object (e_table); 1694 string = e_table_state_save_to_string (state); 1695 g_object_unref (state); 1696 return string; 1697 } 1698 1699 /** 1700 * e_table_save_state: 1701 * @e_table: The #ETable to act on 1702 * @filename: name of the file to save to 1703 * 1704 * Saves the state of the @e_table object into the file pointed by 1705 * @filename. 1706 * 1707 **/ 1708 void 1709 e_table_save_state (ETable *e_table, 1710 const gchar *filename) 1711 { 1712 ETableState *state; 1713 1714 state = e_table_get_state_object (e_table); 1715 e_table_state_save_to_file (state, filename); 1716 g_object_unref (state); 1717 } 1718 1719 static void 1720 et_selection_model_selection_changed (ETableGroup *etg, 1721 ETable *et) 1722 { 1723 g_signal_emit (et, et_signals[SELECTION_CHANGE], 0); 1724 } 1725 1726 static void 1727 et_selection_model_selection_row_changed (ETableGroup *etg, 1728 gint row, 1729 ETable *et) 1730 { 1731 g_signal_emit (et, et_signals[SELECTION_CHANGE], 0); 1732 } 1733 1734 static ETable * 1735 et_real_construct (ETable *e_table, 1736 ETableModel *etm, 1737 ETableExtras *ete, 1738 ETableSpecification *specification, 1739 ETableState *state) 1740 { 1741 gint row = 0; 1742 gint col_count, i; 1743 GValue *val; 1744 GtkAdjustment *adjustment; 1745 GtkScrollable *scrollable; 1746 1747 val = g_new0 (GValue, 1); 1748 g_value_init (val, G_TYPE_OBJECT); 1749 1750 if (ete) 1751 g_object_ref (ete); 1752 else { 1753 ete = e_table_extras_new (); 1754 } 1755 1756 e_table->domain = g_strdup (specification->domain); 1757 1758 e_table->use_click_to_add = specification->click_to_add; 1759 e_table->use_click_to_add_end = specification->click_to_add_end; 1760 e_table->click_to_add_message = specification->click_to_add_message ? 1761 g_strdup ( 1762 dgettext (e_table->domain, 1763 specification->click_to_add_message)) : NULL; 1764 e_table->alternating_row_colors = specification->alternating_row_colors; 1765 e_table->horizontal_draw_grid = specification->horizontal_draw_grid; 1766 e_table->vertical_draw_grid = specification->vertical_draw_grid; 1767 e_table->draw_focus = specification->draw_focus; 1768 e_table->cursor_mode = specification->cursor_mode; 1769 e_table->full_header = e_table_spec_to_full_header (specification, ete); 1770 1771 col_count = e_table_header_count (e_table->full_header); 1772 for (i = 0; i < col_count; i++) { 1773 ETableCol *col = e_table_header_get_column (e_table->full_header, i); 1774 if (col && col->search) { 1775 e_table->current_search_col = col; 1776 e_table->search_col_set = TRUE; 1777 break; 1778 } 1779 } 1780 1781 e_table->model = etm; 1782 g_object_ref (etm); 1783 1784 connect_header (e_table, state); 1785 e_table->horizontal_scrolling = specification->horizontal_scrolling; 1786 e_table->horizontal_resize = specification->horizontal_resize; 1787 e_table->allow_grouping = specification->allow_grouping; 1788 1789 e_table->sort_info = g_object_ref (state->sort_info); 1790 1791 e_table_sort_info_set_can_group ( 1792 e_table->sort_info, e_table->allow_grouping); 1793 1794 e_table->group_info_change_id = g_signal_connect ( 1795 e_table->sort_info, "group_info_changed", 1796 G_CALLBACK (group_info_changed), e_table); 1797 1798 e_table->sort_info_change_id = g_signal_connect ( 1799 e_table->sort_info, "sort_info_changed", 1800 G_CALLBACK (sort_info_changed), e_table); 1801 1802 g_value_set_object (val, e_table->sort_info); 1803 g_object_set_property (G_OBJECT (e_table->header), "sort_info", val); 1804 g_free (val); 1805 1806 e_table->sorter = e_table_sorter_new ( 1807 etm, e_table->full_header, e_table->sort_info); 1808 1809 g_object_set ( 1810 e_table->selection, 1811 "model", etm, 1812 "selection_mode", specification->selection_mode, 1813 "cursor_mode", specification->cursor_mode, 1814 "sorter", e_table->sorter, 1815 "header", e_table->header, 1816 NULL); 1817 1818 g_signal_connect ( 1819 e_table->selection, "selection_changed", 1820 G_CALLBACK (et_selection_model_selection_changed), e_table); 1821 g_signal_connect ( 1822 e_table->selection, "selection_row_changed", 1823 G_CALLBACK (et_selection_model_selection_row_changed), e_table); 1824 1825 if (!specification->no_headers) 1826 e_table_setup_header (e_table); 1827 1828 e_table_setup_table ( 1829 e_table, e_table->full_header, e_table->header, etm); 1830 e_table_fill_table (e_table, etm); 1831 1832 scrollable = GTK_SCROLLABLE (e_table->table_canvas); 1833 1834 adjustment = gtk_scrollable_get_vadjustment (scrollable); 1835 gtk_adjustment_set_step_increment (adjustment, 20); 1836 1837 adjustment = gtk_scrollable_get_hadjustment (scrollable); 1838 gtk_adjustment_set_step_increment (adjustment, 20); 1839 1840 if (!specification->no_headers) { 1841 /* The header */ 1842 gtk_table_attach ( 1843 GTK_TABLE (e_table), GTK_WIDGET (e_table->header_canvas), 1844 0, 1, 0 + row, 1 + row, 1845 GTK_FILL | GTK_EXPAND, 1846 GTK_FILL, 0, 0); 1847 row++; 1848 } 1849 gtk_table_attach ( 1850 GTK_TABLE (e_table), GTK_WIDGET (e_table->table_canvas), 1851 0, 1, 0 + row, 1 + row, 1852 GTK_FILL | GTK_EXPAND, 1853 GTK_FILL | GTK_EXPAND, 1854 0, 0); 1855 1856 g_object_unref (ete); 1857 1858 return e_table; 1859 } 1860 1861 /** 1862 * e_table_construct: 1863 * @e_table: The newly created #ETable object. 1864 * @etm: The model for this table. 1865 * @ete: An optional #ETableExtras. (%NULL is valid.) 1866 * @spec_str: The spec. 1867 * @state_str: An optional state. (%NULL is valid.) 1868 * 1869 * This is the internal implementation of e_table_new() for use by 1870 * subclasses or language bindings. See e_table_new() for details. 1871 * 1872 * Return value: 1873 * The passed in value @e_table or %NULL if there's an error. 1874 **/ 1875 ETable * 1876 e_table_construct (ETable *e_table, 1877 ETableModel *etm, 1878 ETableExtras *ete, 1879 const gchar *spec_str, 1880 const gchar *state_str) 1881 { 1882 ETableSpecification *specification; 1883 ETableState *state; 1884 1885 g_return_val_if_fail (E_IS_TABLE (e_table), NULL); 1886 g_return_val_if_fail (E_IS_TABLE_MODEL (etm), NULL); 1887 g_return_val_if_fail (ete == NULL || E_IS_TABLE_EXTRAS (ete), NULL); 1888 g_return_val_if_fail (spec_str != NULL, NULL); 1889 1890 g_object_ref (etm); 1891 1892 specification = e_table_specification_new (); 1893 g_object_ref (specification); 1894 if (!e_table_specification_load_from_string (specification, spec_str)) { 1895 g_object_unref (specification); 1896 return NULL; 1897 } 1898 1899 if (state_str) { 1900 state = e_table_state_new (); 1901 g_object_ref (state); 1902 e_table_state_load_from_string (state, state_str); 1903 if (state->col_count <= 0) { 1904 g_object_unref (state); 1905 state = specification->state; 1906 g_object_ref (state); 1907 } 1908 } else { 1909 state = specification->state; 1910 g_object_ref (state); 1911 } 1912 1913 e_table = et_real_construct (e_table, etm, ete, specification, state); 1914 1915 e_table->spec = specification; 1916 g_object_unref (state); 1917 1918 return e_table; 1919 } 1920 1921 /** 1922 * e_table_construct_from_spec_file: 1923 * @e_table: The newly created #ETable object. 1924 * @etm: The model for this table. 1925 * @ete: An optional #ETableExtras. (%NULL is valid.) 1926 * @spec_fn: The filename of the spec. 1927 * @state_fn: An optional state file. (%NULL is valid.) 1928 * 1929 * This is the internal implementation of e_table_new_from_spec_file() 1930 * for use by subclasses or language bindings. See 1931 * e_table_new_from_spec_file() for details. 1932 * 1933 * Return value: 1934 * The passed in value @e_table or %NULL if there's an error. 1935 **/ 1936 ETable * 1937 e_table_construct_from_spec_file (ETable *e_table, 1938 ETableModel *etm, 1939 ETableExtras *ete, 1940 const gchar *spec_fn, 1941 const gchar *state_fn) 1942 { 1943 ETableSpecification *specification; 1944 ETableState *state; 1945 1946 g_return_val_if_fail (E_IS_TABLE (e_table), NULL); 1947 g_return_val_if_fail (E_IS_TABLE_MODEL (etm), NULL); 1948 g_return_val_if_fail (ete == NULL || E_IS_TABLE_EXTRAS (ete), NULL); 1949 g_return_val_if_fail (spec_fn != NULL, NULL); 1950 1951 specification = e_table_specification_new (); 1952 if (!e_table_specification_load_from_file (specification, spec_fn)) { 1953 g_object_unref (specification); 1954 return NULL; 1955 } 1956 1957 if (state_fn) { 1958 state = e_table_state_new (); 1959 if (!e_table_state_load_from_file (state, state_fn)) { 1960 g_object_unref (state); 1961 state = specification->state; 1962 g_object_ref (state); 1963 } 1964 if (state->col_count <= 0) { 1965 g_object_unref (state); 1966 state = specification->state; 1967 g_object_ref (state); 1968 } 1969 } else { 1970 state = specification->state; 1971 g_object_ref (state); 1972 } 1973 1974 e_table = et_real_construct (e_table, etm, ete, specification, state); 1975 1976 e_table->spec = specification; 1977 g_object_unref (state); 1978 1979 return e_table; 1980 } 1981 1982 /** 1983 * e_table_new: 1984 * @etm: The model for this table. 1985 * @ete: An optional #ETableExtras. (%NULL is valid.) 1986 * @spec: The spec. 1987 * @state: An optional state. (%NULL is valid.) 1988 * 1989 * This function creates an #ETable from the given parameters. The 1990 * #ETableModel is a table model to be represented. The #ETableExtras 1991 * is an optional set of pixbufs, cells, and sorting functions to be 1992 * used when interpreting the spec. If you pass in %NULL it uses the 1993 * default #ETableExtras. (See e_table_extras_new()). 1994 * 1995 * @spec is the specification of the set of viewable columns and the 1996 * default sorting state and such. @state is an optional string 1997 * specifying the current sorting state and such. If @state is NULL, 1998 * then the default state from the spec will be used. 1999 * 2000 * Return value: 2001 * The newly created #ETable or %NULL if there's an error. 2002 **/ 2003 GtkWidget * 2004 e_table_new (ETableModel *etm, 2005 ETableExtras *ete, 2006 const gchar *spec, 2007 const gchar *state) 2008 { 2009 ETable *e_table; 2010 2011 g_return_val_if_fail (E_IS_TABLE_MODEL (etm), NULL); 2012 g_return_val_if_fail (ete == NULL || E_IS_TABLE_EXTRAS (ete), NULL); 2013 g_return_val_if_fail (spec != NULL, NULL); 2014 2015 e_table = g_object_new (E_TYPE_TABLE, NULL); 2016 2017 e_table = e_table_construct (e_table, etm, ete, spec, state); 2018 2019 return GTK_WIDGET (e_table); 2020 } 2021 2022 /** 2023 * e_table_new_from_spec_file: 2024 * @etm: The model for this table. 2025 * @ete: An optional #ETableExtras. (%NULL is valid.) 2026 * @spec_fn: The filename of the spec. 2027 * @state_fn: An optional state file. (%NULL is valid.) 2028 * 2029 * This is very similar to e_table_new(), except instead of passing in 2030 * strings you pass in the file names of the spec and state to load. 2031 * 2032 * @spec_fn is the filename of the spec to load. If this file doesn't 2033 * exist, e_table_new_from_spec_file will return %NULL. 2034 * 2035 * @state_fn is the filename of the initial state to load. If this is 2036 * %NULL or if the specified file doesn't exist, the default state 2037 * from the spec file is used. 2038 * 2039 * Return value: 2040 * The newly created #ETable or %NULL if there's an error. 2041 **/ 2042 GtkWidget * 2043 e_table_new_from_spec_file (ETableModel *etm, 2044 ETableExtras *ete, 2045 const gchar *spec_fn, 2046 const gchar *state_fn) 2047 { 2048 ETable *e_table; 2049 2050 g_return_val_if_fail (E_IS_TABLE_MODEL (etm), NULL); 2051 g_return_val_if_fail (ete == NULL || E_IS_TABLE_EXTRAS (ete), NULL); 2052 g_return_val_if_fail (spec_fn != NULL, NULL); 2053 2054 e_table = g_object_new (E_TYPE_TABLE, NULL); 2055 2056 e_table = e_table_construct_from_spec_file (e_table, etm, ete, spec_fn, state_fn); 2057 2058 return GTK_WIDGET (e_table); 2059 } 2060 2061 /** 2062 * e_table_set_cursor_row: 2063 * @e_table: The #ETable to set the cursor row of 2064 * @row: The row number 2065 * 2066 * Sets the cursor row and the selection to the given row number. 2067 **/ 2068 void 2069 e_table_set_cursor_row (ETable *e_table, 2070 gint row) 2071 { 2072 g_return_if_fail (E_IS_TABLE (e_table)); 2073 g_return_if_fail (row >= 0); 2074 2075 g_object_set ( 2076 e_table->selection, 2077 "cursor_row", row, 2078 NULL); 2079 } 2080 2081 /** 2082 * e_table_get_cursor_row: 2083 * @e_table: The #ETable to query 2084 * 2085 * Calculates the cursor row. -1 means that we don't have a cursor. 2086 * 2087 * Return value: 2088 * Cursor row 2089 **/ 2090 gint 2091 e_table_get_cursor_row (ETable *e_table) 2092 { 2093 gint row; 2094 g_return_val_if_fail (E_IS_TABLE (e_table), -1); 2095 2096 g_object_get ( 2097 e_table->selection, 2098 "cursor_row", &row, 2099 NULL); 2100 return row; 2101 } 2102 2103 /** 2104 * e_table_selected_row_foreach: 2105 * @e_table: The #ETable to act on 2106 * @callback: The callback function to call 2107 * @closure: The value passed to the callback's closure argument 2108 * 2109 * Calls the given @callback function once for every selected row. 2110 * 2111 * If you change the selection or delete or add rows to the table 2112 * during these callbacks, problems can occur. A standard thing to do 2113 * is to create a list of rows or objects the function is called upon 2114 * and then act upon that list. (In inverse order if it's rows.) 2115 **/ 2116 void 2117 e_table_selected_row_foreach (ETable *e_table, 2118 EForeachFunc callback, 2119 gpointer closure) 2120 { 2121 g_return_if_fail (E_IS_TABLE (e_table)); 2122 2123 e_selection_model_foreach (E_SELECTION_MODEL (e_table->selection), 2124 callback, 2125 closure); 2126 } 2127 2128 /** 2129 * e_table_selected_count: 2130 * @e_table: The #ETable to query 2131 * 2132 * Counts the number of selected rows. 2133 * 2134 * Return value: 2135 * The number of rows selected. 2136 **/ 2137 gint 2138 e_table_selected_count (ETable *e_table) 2139 { 2140 g_return_val_if_fail (E_IS_TABLE (e_table), -1); 2141 2142 return e_selection_model_selected_count (E_SELECTION_MODEL (e_table->selection)); 2143 } 2144 2145 /** 2146 * e_table_select_all: 2147 * @table: The #ETable to modify 2148 * 2149 * Selects all the rows in @table. 2150 **/ 2151 void 2152 e_table_select_all (ETable *table) 2153 { 2154 g_return_if_fail (E_IS_TABLE (table)); 2155 2156 e_selection_model_select_all (E_SELECTION_MODEL (table->selection)); 2157 } 2158 2159 /** 2160 * e_table_invert_selection: 2161 * @table: The #ETable to modify 2162 * 2163 * Inverts the selection in @table. 2164 **/ 2165 void 2166 e_table_invert_selection (ETable *table) 2167 { 2168 g_return_if_fail (E_IS_TABLE (table)); 2169 2170 e_selection_model_invert_selection (E_SELECTION_MODEL (table->selection)); 2171 } 2172 2173 /** 2174 * e_table_get_printable: 2175 * @e_table: #ETable to query 2176 * 2177 * Used for printing your #ETable. 2178 * 2179 * Return value: 2180 * The #EPrintable to print. 2181 **/ 2182 EPrintable * 2183 e_table_get_printable (ETable *e_table) 2184 { 2185 g_return_val_if_fail (E_IS_TABLE (e_table), NULL); 2186 2187 return e_table_group_get_printable (e_table->group); 2188 } 2189 2190 /** 2191 * e_table_right_click_up: 2192 * @table: The #ETable to modify. 2193 * 2194 * Call this function when you're done handling the right click if you 2195 * return TRUE from the "right_click" signal. 2196 **/ 2197 void 2198 e_table_right_click_up (ETable *table) 2199 { 2200 e_selection_model_right_click_up (E_SELECTION_MODEL (table->selection)); 2201 } 2202 2203 /** 2204 * e_table_commit_click_to_add: 2205 * @table: The #ETable to modify 2206 * 2207 * Commits the current values in the click to add to the table. 2208 **/ 2209 void 2210 e_table_commit_click_to_add (ETable *table) 2211 { 2212 et_eti_leave_edit (table); 2213 if (table->click_to_add) 2214 e_table_click_to_add_commit ( 2215 E_TABLE_CLICK_TO_ADD (table->click_to_add)); 2216 } 2217 2218 static void 2219 et_get_property (GObject *object, 2220 guint property_id, 2221 GValue *value, 2222 GParamSpec *pspec) 2223 { 2224 ETable *etable = E_TABLE (object); 2225 2226 switch (property_id) { 2227 case PROP_MODEL: 2228 g_value_set_object (value, etable->model); 2229 break; 2230 case PROP_UNIFORM_ROW_HEIGHT: 2231 g_value_set_boolean (value, etable->uniform_row_height); 2232 break; 2233 case PROP_ALWAYS_SEARCH: 2234 g_value_set_boolean (value, etable->always_search); 2235 break; 2236 case PROP_USE_CLICK_TO_ADD: 2237 g_value_set_boolean (value, etable->use_click_to_add); 2238 break; 2239 case PROP_HADJUSTMENT: 2240 if (etable->table_canvas) 2241 g_object_get_property ( 2242 G_OBJECT (etable->table_canvas), 2243 "hadjustment", value); 2244 else 2245 g_value_set_object (value, NULL); 2246 break; 2247 case PROP_VADJUSTMENT: 2248 if (etable->table_canvas) 2249 g_object_get_property ( 2250 G_OBJECT (etable->table_canvas), 2251 "vadjustment", value); 2252 else 2253 g_value_set_object (value, NULL); 2254 break; 2255 case PROP_HSCROLL_POLICY: 2256 if (etable->table_canvas) 2257 g_object_get_property ( 2258 G_OBJECT (etable->table_canvas), 2259 "hscroll-policy", value); 2260 else 2261 g_value_set_enum (value, 0); 2262 break; 2263 case PROP_VSCROLL_POLICY: 2264 if (etable->table_canvas) 2265 g_object_get_property ( 2266 G_OBJECT (etable->table_canvas), 2267 "vscroll-policy", value); 2268 else 2269 g_value_set_enum (value, 0); 2270 break; 2271 default: 2272 break; 2273 } 2274 } 2275 2276 typedef struct { 2277 gchar *arg; 2278 gboolean setting; 2279 } bool_closure; 2280 2281 static void 2282 et_set_property (GObject *object, 2283 guint property_id, 2284 const GValue *value, 2285 GParamSpec *pspec) 2286 { 2287 ETable *etable = E_TABLE (object); 2288 2289 switch (property_id) { 2290 case PROP_LENGTH_THRESHOLD: 2291 etable->length_threshold = g_value_get_int (value); 2292 if (etable->group) { 2293 gnome_canvas_item_set ( 2294 GNOME_CANVAS_ITEM (etable->group), 2295 "length_threshold", 2296 etable->length_threshold, 2297 NULL); 2298 } 2299 break; 2300 case PROP_UNIFORM_ROW_HEIGHT: 2301 etable->uniform_row_height = g_value_get_boolean (value); 2302 if (etable->group) { 2303 gnome_canvas_item_set ( 2304 GNOME_CANVAS_ITEM (etable->group), 2305 "uniform_row_height", 2306 etable->uniform_row_height, 2307 NULL); 2308 } 2309 break; 2310 case PROP_ALWAYS_SEARCH: 2311 if (etable->always_search == g_value_get_boolean (value)) 2312 return; 2313 2314 etable->always_search = g_value_get_boolean (value); 2315 clear_current_search_col (etable); 2316 break; 2317 case PROP_USE_CLICK_TO_ADD: 2318 if (etable->use_click_to_add == g_value_get_boolean (value)) 2319 return; 2320 2321 etable->use_click_to_add = g_value_get_boolean (value); 2322 clear_current_search_col (etable); 2323 2324 if (etable->use_click_to_add) { 2325 etable->click_to_add = gnome_canvas_item_new ( 2326 GNOME_CANVAS_GROUP (etable->canvas_vbox), 2327 e_table_click_to_add_get_type (), 2328 "header", etable->header, 2329 "model", etable->model, 2330 "message", etable->click_to_add_message, 2331 NULL); 2332 2333 if (etable->use_click_to_add_end) 2334 e_canvas_vbox_add_item ( 2335 E_CANVAS_VBOX (etable->canvas_vbox), 2336 etable->click_to_add); 2337 else 2338 e_canvas_vbox_add_item_start ( 2339 E_CANVAS_VBOX (etable->canvas_vbox), 2340 etable->click_to_add); 2341 2342 g_signal_connect ( 2343 etable->click_to_add, "cursor_change", 2344 G_CALLBACK (click_to_add_cursor_change), 2345 etable); 2346 } else { 2347 g_object_run_dispose (G_OBJECT (etable->click_to_add)); 2348 etable->click_to_add = NULL; 2349 } 2350 break; 2351 case PROP_HADJUSTMENT: 2352 if (etable->table_canvas) 2353 g_object_set_property ( 2354 G_OBJECT (etable->table_canvas), 2355 "hadjustment", value); 2356 break; 2357 case PROP_VADJUSTMENT: 2358 if (etable->table_canvas) 2359 g_object_set_property ( 2360 G_OBJECT (etable->table_canvas), 2361 "vadjustment", value); 2362 break; 2363 case PROP_HSCROLL_POLICY: 2364 if (etable->table_canvas) 2365 g_object_set_property ( 2366 G_OBJECT (etable->table_canvas), 2367 "hscroll-policy", value); 2368 break; 2369 case PROP_VSCROLL_POLICY: 2370 if (etable->table_canvas) 2371 g_object_set_property ( 2372 G_OBJECT (etable->table_canvas), 2373 "vscroll-policy", value); 2374 break; 2375 } 2376 } 2377 2378 /** 2379 * e_table_get_next_row: 2380 * @e_table: The #ETable to query 2381 * @model_row: The model row to go from 2382 * 2383 * This function is used when your table is sorted, but you're using 2384 * model row numbers. It returns the next row in sorted order as a model row. 2385 * 2386 * Return value: 2387 * The model row number. 2388 **/ 2389 gint 2390 e_table_get_next_row (ETable *e_table, 2391 gint model_row) 2392 { 2393 g_return_val_if_fail (E_IS_TABLE (e_table), -1); 2394 2395 if (e_table->sorter) { 2396 gint i; 2397 i = e_sorter_model_to_sorted (E_SORTER (e_table->sorter), model_row); 2398 i++; 2399 if (i < e_table_model_row_count (e_table->model)) { 2400 return e_sorter_sorted_to_model (E_SORTER (e_table->sorter), i); 2401 } else 2402 return -1; 2403 } else 2404 if (model_row < e_table_model_row_count (e_table->model) - 1) 2405 return model_row + 1; 2406 else 2407 return -1; 2408 } 2409 2410 /** 2411 * e_table_get_prev_row: 2412 * @e_table: The #ETable to query 2413 * @model_row: The model row to go from 2414 * 2415 * This function is used when your table is sorted, but you're using 2416 * model row numbers. It returns the previous row in sorted order as 2417 * a model row. 2418 * 2419 * Return value: 2420 * The model row number. 2421 **/ 2422 gint 2423 e_table_get_prev_row (ETable *e_table, 2424 gint model_row) 2425 { 2426 g_return_val_if_fail (E_IS_TABLE (e_table), -1); 2427 2428 if (e_table->sorter) { 2429 gint i; 2430 i = e_sorter_model_to_sorted (E_SORTER (e_table->sorter), model_row); 2431 i--; 2432 if (i >= 0) 2433 return e_sorter_sorted_to_model (E_SORTER (e_table->sorter), i); 2434 else 2435 return -1; 2436 } else 2437 return model_row - 1; 2438 } 2439 2440 /** 2441 * e_table_model_to_view_row: 2442 * @e_table: The #ETable to query 2443 * @model_row: The model row number 2444 * 2445 * Turns a model row into a view row. 2446 * 2447 * Return value: 2448 * The view row number. 2449 **/ 2450 gint 2451 e_table_model_to_view_row (ETable *e_table, 2452 gint model_row) 2453 { 2454 g_return_val_if_fail (E_IS_TABLE (e_table), -1); 2455 2456 if (e_table->sorter) 2457 return e_sorter_model_to_sorted (E_SORTER (e_table->sorter), model_row); 2458 else 2459 return model_row; 2460 } 2461 2462 /** 2463 * e_table_view_to_model_row: 2464 * @e_table: The #ETable to query 2465 * @view_row: The view row number 2466 * 2467 * Turns a view row into a model row. 2468 * 2469 * Return value: 2470 * The model row number. 2471 **/ 2472 gint 2473 e_table_view_to_model_row (ETable *e_table, 2474 gint view_row) 2475 { 2476 g_return_val_if_fail (E_IS_TABLE (e_table), -1); 2477 2478 if (e_table->sorter) 2479 return e_sorter_sorted_to_model (E_SORTER (e_table->sorter), view_row); 2480 else 2481 return view_row; 2482 } 2483 2484 /** 2485 * e_table_get_cell_at: 2486 * @table: An #ETable widget 2487 * @x: X coordinate for the pixel 2488 * @y: Y coordinate for the pixel 2489 * @row_return: Pointer to return the row value 2490 * @col_return: Pointer to return the column value 2491 * 2492 * Return the row and column for the cell in which the pixel at (@x, @y) is 2493 * contained. 2494 **/ 2495 void 2496 e_table_get_cell_at (ETable *table, 2497 gint x, 2498 gint y, 2499 gint *row_return, 2500 gint *col_return) 2501 { 2502 GtkAdjustment *adjustment; 2503 GtkScrollable *scrollable; 2504 2505 g_return_if_fail (E_IS_TABLE (table)); 2506 g_return_if_fail (row_return != NULL); 2507 g_return_if_fail (col_return != NULL); 2508 2509 /* FIXME it would be nice if it could handle a NULL row_return or 2510 * col_return gracefully. */ 2511 2512 scrollable = GTK_SCROLLABLE (table->table_canvas); 2513 2514 adjustment = gtk_scrollable_get_hadjustment (scrollable); 2515 x += gtk_adjustment_get_value (adjustment); 2516 2517 adjustment = gtk_scrollable_get_vadjustment (scrollable); 2518 y += gtk_adjustment_get_value (adjustment); 2519 2520 e_table_group_compute_location ( 2521 table->group, &x, &y, row_return, col_return); 2522 } 2523 2524 /** 2525 * e_table_get_cell_geometry: 2526 * @table: The #ETable. 2527 * @row: The row to get the geometry of. 2528 * @col: The col to get the geometry of. 2529 * @x_return: Returns the x coordinate of the upper left hand corner 2530 * of the cell with respect to the widget. 2531 * @y_return: Returns the y coordinate of the upper left hand corner 2532 * of the cell with respect to the widget. 2533 * @width_return: Returns the width of the cell. 2534 * @height_return: Returns the height of the cell. 2535 * 2536 * Returns the x, y, width, and height of the given cell. These can 2537 * all be #NULL and they just won't be set. 2538 **/ 2539 void 2540 e_table_get_cell_geometry (ETable *table, 2541 gint row, 2542 gint col, 2543 gint *x_return, 2544 gint *y_return, 2545 gint *width_return, 2546 gint *height_return) 2547 { 2548 GtkAllocation allocation; 2549 GtkAdjustment *adjustment; 2550 GtkScrollable *scrollable; 2551 2552 g_return_if_fail (E_IS_TABLE (table)); 2553 2554 scrollable = GTK_SCROLLABLE (table->table_canvas); 2555 2556 e_table_group_get_cell_geometry ( 2557 table->group, &row, &col, x_return, y_return, 2558 width_return, height_return); 2559 2560 if (x_return && table->table_canvas) { 2561 adjustment = gtk_scrollable_get_hadjustment (scrollable); 2562 (*x_return) -= gtk_adjustment_get_value (adjustment); 2563 } 2564 2565 if (y_return) { 2566 if (table->table_canvas) { 2567 adjustment = gtk_scrollable_get_vadjustment (scrollable); 2568 (*y_return) -= gtk_adjustment_get_value (adjustment); 2569 } 2570 2571 if (table->header_canvas) { 2572 gtk_widget_get_allocation ( 2573 GTK_WIDGET (table->header_canvas), 2574 &allocation); 2575 (*y_return) += allocation.height; 2576 } 2577 } 2578 } 2579 2580 /** 2581 * e_table_get_mouse_over_cell: 2582 * 2583 * Similar to e_table_get_cell_at, only here we check 2584 * based on the mouse motion information in the group. 2585 **/ 2586 void 2587 e_table_get_mouse_over_cell (ETable *table, 2588 gint *row, 2589 gint *col) 2590 { 2591 g_return_if_fail (E_IS_TABLE (table)); 2592 2593 if (!table->group) 2594 return; 2595 2596 e_table_group_get_mouse_over (table->group, row, col); 2597 } 2598 2599 /** 2600 * e_table_get_selection_model: 2601 * @table: The #ETable to query 2602 * 2603 * Returns the table's #ESelectionModel in case you want to access it 2604 * directly. 2605 * 2606 * Return value: 2607 * The #ESelectionModel. 2608 **/ 2609 ESelectionModel * 2610 e_table_get_selection_model (ETable *table) 2611 { 2612 g_return_val_if_fail (E_IS_TABLE (table), NULL); 2613 2614 return E_SELECTION_MODEL (table->selection); 2615 } 2616 2617 struct _ETableDragSourceSite 2618 { 2619 GdkModifierType start_button_mask; 2620 GtkTargetList *target_list; /* Targets for drag data */ 2621 GdkDragAction actions; /* Possible actions */ 2622 GdkPixbuf *pixbuf; /* Icon for drag data */ 2623 2624 /* Stored button press information to detect drag beginning */ 2625 gint state; 2626 gint x, y; 2627 gint row, col; 2628 }; 2629 2630 typedef enum 2631 { 2632 GTK_DRAG_STATUS_DRAG, 2633 GTK_DRAG_STATUS_WAIT, 2634 GTK_DRAG_STATUS_DROP 2635 } GtkDragStatus; 2636 2637 typedef struct _GtkDragDestInfo GtkDragDestInfo; 2638 typedef struct _GtkDragSourceInfo GtkDragSourceInfo; 2639 2640 struct _GtkDragDestInfo 2641 { 2642 GtkWidget *widget; /* Widget in which drag is in */ 2643 GdkDragContext *context; /* Drag context */ 2644 GtkDragSourceInfo *proxy_source; /* Set if this is a proxy drag */ 2645 GtkSelectionData *proxy_data; /* Set while retrieving proxied data */ 2646 guint dropped : 1; /* Set after we receive a drop */ 2647 guint32 proxy_drop_time; /* Timestamp for proxied drop */ 2648 guint proxy_drop_wait : 1; /* Set if we are waiting for a 2649 * status reply before sending 2650 * a proxied drop on. 2651 */ 2652 gint drop_x, drop_y; /* Position of drop */ 2653 }; 2654 2655 struct _GtkDragSourceInfo 2656 { 2657 GtkWidget *widget; 2658 GtkTargetList *target_list; /* Targets for drag data */ 2659 GdkDragAction possible_actions; /* Actions allowed by source */ 2660 GdkDragContext *context; /* drag context */ 2661 GtkWidget *icon_window; /* Window for drag */ 2662 GtkWidget *ipc_widget; /* GtkInvisible for grab, message passing */ 2663 GdkCursor *cursor; /* Cursor for drag */ 2664 gint hot_x, hot_y; /* Hot spot for drag */ 2665 gint button; /* mouse button starting drag */ 2666 2667 GtkDragStatus status; /* drag status */ 2668 GdkEvent *last_event; /* motion event waiting for response */ 2669 2670 gint start_x, start_y; /* Initial position */ 2671 gint cur_x, cur_y; /* Current Position */ 2672 2673 GList *selections; /* selections we've claimed */ 2674 2675 GtkDragDestInfo *proxy_dest; /* Set if this is a proxy drag */ 2676 2677 guint drop_timeout; /* Timeout for aborting drop */ 2678 guint destroy_icon : 1; /* If true, destroy icon_window 2679 */ 2680 }; 2681 2682 /* Drag & drop stuff. */ 2683 /* Target */ 2684 2685 /** 2686 * e_table_drag_get_data: 2687 * @table: 2688 * @row: 2689 * @col: 2690 * @context: 2691 * @target: 2692 * @time: 2693 * 2694 * 2695 **/ 2696 void 2697 e_table_drag_get_data (ETable *table, 2698 gint row, 2699 gint col, 2700 GdkDragContext *context, 2701 GdkAtom target, 2702 guint32 time) 2703 { 2704 g_return_if_fail (E_IS_TABLE (table)); 2705 2706 gtk_drag_get_data ( 2707 GTK_WIDGET (table), 2708 context, 2709 target, 2710 time); 2711 } 2712 2713 /** 2714 * e_table_drag_highlight: 2715 * @table: The #ETable to highlight 2716 * @row: The row number of the cell to highlight 2717 * @col: The column number of the cell to highlight 2718 * 2719 * Set col to -1 to highlight the entire row. If row is -1, this is 2720 * identical to e_table_drag_unhighlight(). 2721 **/ 2722 void 2723 e_table_drag_highlight (ETable *table, 2724 gint row, 2725 gint col) 2726 { 2727 GtkAllocation allocation; 2728 GtkAdjustment *adjustment; 2729 GtkScrollable *scrollable; 2730 GtkStyle *style; 2731 2732 g_return_if_fail (E_IS_TABLE (table)); 2733 2734 scrollable = GTK_SCROLLABLE (table->table_canvas); 2735 style = gtk_widget_get_style (GTK_WIDGET (table)); 2736 gtk_widget_get_allocation (GTK_WIDGET (scrollable), &allocation); 2737 2738 if (row != -1) { 2739 gint x, y, width, height; 2740 if (col == -1) { 2741 e_table_get_cell_geometry (table, row, 0, &x, &y, &width, &height); 2742 x = 0; 2743 width = allocation.width; 2744 } else { 2745 e_table_get_cell_geometry (table, row, col, &x, &y, &width, &height); 2746 adjustment = gtk_scrollable_get_hadjustment (scrollable); 2747 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)

2748 } 2749 2750 adjustment = gtk_scrollable_get_vadjustment (scrollable); 2751 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)

2752 2753 if (table->drop_highlight == NULL) { 2754 table->drop_highlight = gnome_canvas_item_new ( 2755 gnome_canvas_root (table->table_canvas), 2756 gnome_canvas_rect_get_type (), 2757 "fill_color", NULL, 2758 "outline_color_gdk", &style->fg[GTK_STATE_NORMAL], 2759 NULL); 2760 } 2761 gnome_canvas_item_set ( 2762 table->drop_highlight, 2763 "x1", (gdouble) x, 2764 "x2", (gdouble) x + width - 1, 2765 "y1", (gdouble) y, 2766 "y2", (gdouble) y + height - 1, 2767 NULL); 2768 } else { 2769 if (table->drop_highlight) { 2770 g_object_run_dispose (G_OBJECT (table->drop_highlight)); 2771 table->drop_highlight = NULL; 2772 } 2773 } 2774 } 2775 2776 /** 2777 * e_table_drag_unhighlight: 2778 * @table: The #ETable to unhighlight 2779 * 2780 * Removes the highlight from an #ETable. 2781 **/ 2782 void 2783 e_table_drag_unhighlight (ETable *table) 2784 { 2785 g_return_if_fail (E_IS_TABLE (table)); 2786 2787 if (table->drop_highlight) { 2788 g_object_run_dispose (G_OBJECT (table->drop_highlight)); 2789 table->drop_highlight = NULL; 2790 } 2791 } 2792 2793 void 2794 e_table_drag_dest_set (ETable *table, 2795 GtkDestDefaults flags, 2796 const GtkTargetEntry *targets, 2797 gint n_targets, 2798 GdkDragAction actions) 2799 { 2800 g_return_if_fail (E_IS_TABLE (table)); 2801 2802 gtk_drag_dest_set ( 2803 GTK_WIDGET (table), flags, targets, n_targets, actions); 2804 } 2805 2806 void 2807 e_table_drag_dest_set_proxy (ETable *table, 2808 GdkWindow *proxy_window, 2809 GdkDragProtocol protocol, 2810 gboolean use_coordinates) 2811 { 2812 g_return_if_fail (E_IS_TABLE (table)); 2813 2814 gtk_drag_dest_set_proxy ( 2815 GTK_WIDGET (table), proxy_window, protocol, use_coordinates); 2816 } 2817 2818 /* 2819 * There probably should be functions for setting the targets 2820 * as a GtkTargetList 2821 */ 2822 2823 void 2824 e_table_drag_dest_unset (GtkWidget *widget) 2825 { 2826 g_return_if_fail (E_IS_TABLE (widget)); 2827 2828 gtk_drag_dest_unset (widget); 2829 } 2830 2831 /* Source side */ 2832 2833 static gint 2834 et_real_start_drag (ETable *table, 2835 gint row, 2836 gint col, 2837 GdkEvent *event) 2838 { 2839 GtkDragSourceInfo *info; 2840 GdkDragContext *context; 2841 ETableDragSourceSite *site; 2842 2843 if (table->do_drag) { 2844 site = table->site; 2845 2846 site->state = 0; 2847 context = e_table_drag_begin ( 2848 table, row, col, 2849 site->target_list, 2850 site->actions, 2851 1, event); 2852 2853 if (context) { 2854 info = g_dataset_get_data (context, "gtk-info"); 2855 2856 if (info && !info->icon_window) { 2857 if (site->pixbuf) 2858 gtk_drag_set_icon_pixbuf ( 2859 context, 2860 site->pixbuf, 2861 -2, -2); 2862 else 2863 gtk_drag_set_icon_default (context); 2864 } 2865 } 2866 return TRUE; 2867 } 2868 return FALSE; 2869 } 2870 2871 /** 2872 * e_table_drag_source_set: 2873 * @table: The #ETable to set up as a drag site 2874 * @start_button_mask: Mask of allowed buttons to start drag 2875 * @targets: Table of targets for this source 2876 * @n_targets: Number of targets in @targets 2877 * @actions: Actions allowed for this source 2878 * 2879 * Registers this table as a drag site, and possibly adds default behaviors. 2880 **/ 2881 void 2882 e_table_drag_source_set (ETable *table, 2883 GdkModifierType start_button_mask, 2884 const GtkTargetEntry *targets, 2885 gint n_targets, 2886 GdkDragAction actions) 2887 { 2888 ETableDragSourceSite *site; 2889 GtkWidget *canvas; 2890 2891 g_return_if_fail (E_IS_TABLE (table)); 2892 2893 canvas = GTK_WIDGET (table->table_canvas); 2894 site = table->site; 2895 2896 gtk_widget_add_events ( 2897 canvas, 2898 gtk_widget_get_events (canvas) | 2899 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | 2900 GDK_BUTTON_MOTION_MASK | GDK_STRUCTURE_MASK); 2901 2902 table->do_drag = TRUE; 2903 2904 if (site) { 2905 if (site->target_list) 2906 gtk_target_list_unref (site->target_list); 2907 } else { 2908 site = g_new0 (ETableDragSourceSite, 1); 2909 table->site = site; 2910 } 2911 2912 site->start_button_mask = start_button_mask; 2913 2914 if (targets) 2915 site->target_list = gtk_target_list_new (targets, n_targets); 2916 else 2917 site->target_list = NULL; 2918 2919 site->actions = actions; 2920 } 2921 2922 /** 2923 * e_table_drag_source_unset: 2924 * @table: The #ETable to un set up as a drag site 2925 * 2926 * Unregisters this #ETable as a drag site. 2927 **/ 2928 void 2929 e_table_drag_source_unset (ETable *table) 2930 { 2931 ETableDragSourceSite *site; 2932 2933 g_return_if_fail (E_IS_TABLE (table)); 2934 2935 site = table->site; 2936 2937 if (site) { 2938 if (site->target_list) 2939 gtk_target_list_unref (site->target_list); 2940 g_free (site); 2941 table->site = NULL; 2942 } 2943 table->do_drag = FALSE; 2944 } 2945 2946 /* There probably should be functions for setting the targets 2947 * as a GtkTargetList 2948 */ 2949 2950 /** 2951 * e_table_drag_begin: 2952 * @table: The #ETable to drag from 2953 * @row: The row number of the cell 2954 * @col: The col number of the cell 2955 * @targets: The list of targets supported by the drag 2956 * @actions: The available actions supported by the drag 2957 * @button: The button held down for the drag 2958 * @event: The event that initiated the drag 2959 * 2960 * Start a drag from this cell. 2961 * 2962 * Return value: 2963 * The drag context. 2964 **/ 2965 GdkDragContext * 2966 e_table_drag_begin (ETable *table, 2967 gint row, 2968 gint col, 2969 GtkTargetList *targets, 2970 GdkDragAction actions, 2971 gint button, 2972 GdkEvent *event) 2973 { 2974 g_return_val_if_fail (E_IS_TABLE (table), NULL); 2975 2976 table->drag_row = row; 2977 table->drag_col = col; 2978 2979 return gtk_drag_begin ( 2980 GTK_WIDGET (table), targets, actions, button, event); 2981 } 2982 2983 static void 2984 et_drag_begin (GtkWidget *widget, 2985 GdkDragContext *context, 2986 ETable *et) 2987 { 2988 g_signal_emit ( 2989 et, et_signals[TABLE_DRAG_BEGIN], 0, 2990 et->drag_row, et->drag_col, context); 2991 } 2992 2993 static void 2994 et_drag_end (GtkWidget *widget, 2995 GdkDragContext *context, 2996 ETable *et) 2997 { 2998 g_signal_emit ( 2999 et, et_signals[TABLE_DRAG_END], 0, 3000 et->drag_row, et->drag_col, context); 3001 } 3002 3003 static void 3004 et_drag_data_get (GtkWidget *widget, 3005 GdkDragContext *context, 3006 GtkSelectionData *selection_data, 3007 guint info, 3008 guint time, 3009 ETable *et) 3010 { 3011 g_signal_emit ( 3012 et, et_signals[TABLE_DRAG_DATA_GET], 0, 3013 et->drag_row, et->drag_col, context, selection_data, 3014 info, time); 3015 } 3016 3017 static void 3018 et_drag_data_delete (GtkWidget *widget, 3019 GdkDragContext *context, 3020 ETable *et) 3021 { 3022 g_signal_emit ( 3023 et, et_signals[TABLE_DRAG_DATA_DELETE], 0, 3024 et->drag_row, et->drag_col, context); 3025 } 3026 3027 static gboolean 3028 do_drag_motion (ETable *et, 3029 GdkDragContext *context, 3030 gint x, 3031 gint y, 3032 guint time) 3033 { 3034 gboolean ret_val; 3035 gint row = -1, col = -1; 3036 3037 e_table_get_cell_at (et, x, y, &row, &col); 3038 3039 if (row != et->drop_row && col != et->drop_row) { 3040 g_signal_emit ( 3041 et, et_signals[TABLE_DRAG_LEAVE], 0, 3042 et->drop_row, et->drop_col, context, time); 3043 } 3044 3045 et->drop_row = row; 3046 et->drop_col = col; 3047 3048 g_signal_emit ( 3049 et, et_signals[TABLE_DRAG_MOTION], 0, 3050 et->drop_row, et->drop_col, context, x, y, time, &ret_val); 3051 3052 return ret_val; 3053 } 3054 3055 static gboolean 3056 scroll_timeout (gpointer data) 3057 { 3058 ETable *et = data; 3059 gint dx = 0, dy = 0; 3060 GtkAdjustment *adjustment; 3061 GtkScrollable *scrollable; 3062 gdouble old_h_value; 3063 gdouble new_h_value; 3064 gdouble old_v_value; 3065 gdouble new_v_value; 3066 gdouble page_size; 3067 gdouble lower; 3068 gdouble upper; 3069 3070 if (et->scroll_direction & ET_SCROLL_DOWN) 3071 dy += 20; 3072 if (et->scroll_direction & ET_SCROLL_UP) 3073 dy -= 20; 3074 3075 if (et->scroll_direction & ET_SCROLL_RIGHT) 3076 dx += 20; 3077 if (et->scroll_direction & ET_SCROLL_LEFT) 3078 dx -= 20; 3079 3080 scrollable = GTK_SCROLLABLE (et->table_canvas); 3081 3082 adjustment = gtk_scrollable_get_hadjustment (scrollable); 3083 3084 lower = gtk_adjustment_get_lower (adjustment); 3085 upper = gtk_adjustment_get_upper (adjustment); 3086 page_size = gtk_adjustment_get_page_size (adjustment); 3087 3088 old_h_value = gtk_adjustment_get_value (adjustment); 3089 new_h_value = CLAMP (old_h_value + dx, lower, upper - page_size); 3090 3091 gtk_adjustment_set_value (adjustment, new_h_value); 3092 3093 adjustment = gtk_scrollable_get_vadjustment (scrollable); 3094 3095 lower = gtk_adjustment_get_lower (adjustment); 3096 upper = gtk_adjustment_get_upper (adjustment); 3097 page_size = gtk_adjustment_get_page_size (adjustment); 3098 3099 old_v_value = gtk_adjustment_get_value (adjustment); 3100 new_v_value = CLAMP (old_v_value + dy, lower, upper - page_size); 3101 3102 gtk_adjustment_set_value (adjustment, new_v_value); 3103 3104 if (new_h_value != old_h_value || new_v_value != old_v_value) 3105 do_drag_motion ( 3106 et, 3107 et->last_drop_context, 3108 et->last_drop_x, 3109 et->last_drop_y, 3110 et->last_drop_time); 3111 3112 return TRUE; 3113 } 3114 3115 static void 3116 scroll_on (ETable *et, 3117 guint scroll_direction) 3118 { 3119 if (et->scroll_idle_id == 0 || scroll_direction != et->scroll_direction) { 3120 if (et->scroll_idle_id != 0) 3121 g_source_remove (et->scroll_idle_id); 3122 et->scroll_direction = scroll_direction; 3123 et->scroll_idle_id = g_timeout_add (100, scroll_timeout, et); 3124 } 3125 } 3126 3127 static void 3128 scroll_off (ETable *et) 3129 { 3130 if (et->scroll_idle_id) { 3131 g_source_remove (et->scroll_idle_id); 3132 et->scroll_idle_id = 0; 3133 } 3134 } 3135 3136 static void 3137 context_destroyed (gpointer data) 3138 { 3139 ETable *et = data; 3140 /* if (!G_OBJECT_DESTROYED (et)) */ 3141 /* FIXME: */ 3142 { 3143 et->last_drop_x = 0; 3144 et->last_drop_y = 0; 3145 et->last_drop_time = 0; 3146 et->last_drop_context = NULL; 3147 scroll_off (et); 3148 } 3149 g_object_unref (et); 3150 } 3151 3152 static void 3153 context_connect (ETable *et, 3154 GdkDragContext *context) 3155 { 3156 if (g_dataset_get_data (context, "e-table") == NULL) { 3157 g_object_ref (et); 3158 g_dataset_set_data_full (context, "e-table", et, context_destroyed); 3159 } 3160 } 3161 3162 static void 3163 et_drag_leave (GtkWidget *widget, 3164 GdkDragContext *context, 3165 guint time, 3166 ETable *et) 3167 { 3168 g_signal_emit ( 3169 et, et_signals[TABLE_DRAG_LEAVE], 0, 3170 et->drop_row, et->drop_col, context, time); 3171 3172 et->drop_row = -1; 3173 et->drop_col = -1; 3174 3175 scroll_off (et); 3176 } 3177 3178 static gboolean 3179 et_drag_motion (GtkWidget *widget, 3180 GdkDragContext *context, 3181 gint x, 3182 gint y, 3183 guint time, 3184 ETable *et) 3185 { 3186 GtkAllocation allocation; 3187 gboolean ret_val; 3188 guint direction = 0; 3189 3190 gtk_widget_get_allocation (widget, &allocation); 3191 3192 et->last_drop_x = x; 3193 et->last_drop_y = y; 3194 et->last_drop_time = time; 3195 et->last_drop_context = context; 3196 context_connect (et, context); 3197 3198 ret_val = do_drag_motion (et, context, x, y, time); 3199 3200 if (y < 20) 3201 direction |= ET_SCROLL_UP; 3202 if (y > allocation.height - 20) 3203 direction |= ET_SCROLL_DOWN; 3204 if (x < 20) 3205 direction |= ET_SCROLL_LEFT; 3206 if (x > allocation.width - 20) 3207 direction |= ET_SCROLL_RIGHT; 3208 3209 if (direction != 0) 3210 scroll_on (et, direction); 3211 else 3212 scroll_off (et); 3213 3214 return ret_val; 3215 } 3216 3217 static gboolean 3218 et_drag_drop (GtkWidget *widget, 3219 GdkDragContext *context, 3220 gint x, 3221 gint y, 3222 guint time, 3223 ETable *et) 3224 { 3225 gboolean ret_val; 3226 gint row, col; 3227 3228 e_table_get_cell_at (et, x, y, &row, &col); 3229 3230 if (row != et->drop_row && col != et->drop_row) {
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)

3231 g_signal_emit ( 3232 et, et_signals[TABLE_DRAG_LEAVE], 0, 3233 et->drop_row, et->drop_col, context, time); 3234 g_signal_emit ( 3235 et, et_signals[TABLE_DRAG_MOTION], 0, 3236 row, col, context, x, y, time, &ret_val); 3237 } 3238 et->drop_row = row; 3239 et->drop_col = col; 3240 g_signal_emit ( 3241 et, et_signals[TABLE_DRAG_DROP], 0, 3242 et->drop_row, et->drop_col, context, x, y, time, &ret_val); 3243 et->drop_row = -1; 3244 et->drop_col = -1; 3245 3246 scroll_off (et); 3247 3248 return ret_val; 3249 } 3250 3251 static void 3252 et_drag_data_received (GtkWidget *widget, 3253 GdkDragContext *context, 3254 gint x, 3255 gint y, 3256 GtkSelectionData *selection_data, 3257 guint info, 3258 guint time, 3259 ETable *et) 3260 { 3261 gint row, col; 3262 3263 e_table_get_cell_at (et, x, y, &row, &col); 3264 3265 g_signal_emit (
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)

3266 et, et_signals[TABLE_DRAG_DATA_RECEIVED], 0, 3267 row, col, context, x, y, selection_data, info, time); 3268 } 3269 3270 static void 3271 e_table_class_init (ETableClass *class) 3272 { 3273 GObjectClass *object_class; 3274 GtkWidgetClass *widget_class; 3275 3276 object_class = (GObjectClass *) class; 3277 widget_class = (GtkWidgetClass *) class; 3278 3279 object_class->dispose = et_dispose; 3280 object_class->finalize = et_finalize; 3281 object_class->set_property = et_set_property; 3282 object_class->get_property = et_get_property; 3283 3284 widget_class->grab_focus = et_grab_focus; 3285 widget_class->unrealize = et_unrealize; 3286 widget_class->get_preferred_width = et_get_preferred_width; 3287 widget_class->get_preferred_height = et_get_preferred_height; 3288 3289 widget_class->focus = et_focus; 3290 3291 class->cursor_change = NULL; 3292 class->cursor_activated = NULL; 3293 class->selection_change = NULL; 3294 class->double_click = NULL; 3295 class->right_click = NULL; 3296 class->click = NULL; 3297 class->key_press = NULL; 3298 class->start_drag = et_real_start_drag; 3299 class->state_change = NULL; 3300 class->white_space_event = NULL; 3301 3302 class->table_drag_begin = NULL; 3303 class->table_drag_end = NULL; 3304 class->table_drag_data_get = NULL; 3305 class->table_drag_data_delete = NULL; 3306 3307 class->table_drag_leave = NULL; 3308 class->table_drag_motion = NULL; 3309 class->table_drag_drop = NULL; 3310 class->table_drag_data_received = NULL; 3311 3312 et_signals[CURSOR_CHANGE] = g_signal_new ( 3313 "cursor_change", 3314 G_OBJECT_CLASS_TYPE (object_class), 3315 G_SIGNAL_RUN_LAST, 3316 G_STRUCT_OFFSET (ETableClass, cursor_change), 3317 NULL, NULL, 3318 g_cclosure_marshal_VOID__INT, 3319 G_TYPE_NONE, 1, G_TYPE_INT); 3320 3321 et_signals[CURSOR_ACTIVATED] = g_signal_new ( 3322 "cursor_activated", 3323 G_OBJECT_CLASS_TYPE (object_class), 3324 G_SIGNAL_RUN_LAST, 3325 G_STRUCT_OFFSET (ETableClass, cursor_activated), 3326 NULL, NULL, 3327 g_cclosure_marshal_VOID__INT, 3328 G_TYPE_NONE, 1, G_TYPE_INT); 3329 3330 et_signals[SELECTION_CHANGE] = g_signal_new ( 3331 "selection_change", 3332 G_OBJECT_CLASS_TYPE (object_class), 3333 G_SIGNAL_RUN_LAST, 3334 G_STRUCT_OFFSET (ETableClass, selection_change), 3335 NULL, NULL, 3336 g_cclosure_marshal_VOID__VOID, 3337 G_TYPE_NONE, 0); 3338 3339 et_signals[DOUBLE_CLICK] = g_signal_new ( 3340 "double_click", 3341 G_OBJECT_CLASS_TYPE (object_class), 3342 G_SIGNAL_RUN_LAST, 3343 G_STRUCT_OFFSET (ETableClass, double_click), 3344 NULL, NULL, 3345 e_marshal_NONE__INT_INT_BOXED, 3346 G_TYPE_NONE, 3, 3347 G_TYPE_INT, 3348 G_TYPE_INT, 3349 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3350 3351 et_signals[RIGHT_CLICK] = g_signal_new ( 3352 "right_click", 3353 G_OBJECT_CLASS_TYPE (object_class), 3354 G_SIGNAL_RUN_LAST, 3355 G_STRUCT_OFFSET (ETableClass, right_click), 3356 g_signal_accumulator_true_handled, NULL, 3357 e_marshal_BOOLEAN__INT_INT_BOXED, 3358 G_TYPE_BOOLEAN, 3, 3359 G_TYPE_INT, 3360 G_TYPE_INT, 3361 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3362 3363 et_signals[CLICK] = g_signal_new ( 3364 "click", 3365 G_OBJECT_CLASS_TYPE (object_class), 3366 G_SIGNAL_RUN_LAST, 3367 G_STRUCT_OFFSET (ETableClass, click), 3368 g_signal_accumulator_true_handled, NULL, 3369 e_marshal_BOOLEAN__INT_INT_BOXED, 3370 G_TYPE_BOOLEAN, 3, 3371 G_TYPE_INT, 3372 G_TYPE_INT, 3373 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3374 3375 et_signals[KEY_PRESS] = g_signal_new ( 3376 "key_press", 3377 G_OBJECT_CLASS_TYPE (object_class), 3378 G_SIGNAL_RUN_LAST, 3379 G_STRUCT_OFFSET (ETableClass, key_press), 3380 g_signal_accumulator_true_handled, NULL, 3381 e_marshal_BOOLEAN__INT_INT_BOXED, 3382 G_TYPE_BOOLEAN, 3, 3383 G_TYPE_INT, 3384 G_TYPE_INT, 3385 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3386 3387 et_signals[START_DRAG] = g_signal_new ( 3388 "start_drag", 3389 G_OBJECT_CLASS_TYPE (object_class), 3390 G_SIGNAL_RUN_LAST, 3391 G_STRUCT_OFFSET (ETableClass, start_drag), 3392 g_signal_accumulator_true_handled, NULL, 3393 e_marshal_BOOLEAN__INT_INT_BOXED, 3394 G_TYPE_BOOLEAN, 3, 3395 G_TYPE_INT, 3396 G_TYPE_INT, 3397 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3398 3399 et_signals[STATE_CHANGE] = g_signal_new ( 3400 "state_change", 3401 G_OBJECT_CLASS_TYPE (object_class), 3402 G_SIGNAL_RUN_LAST, 3403 G_STRUCT_OFFSET (ETableClass, state_change), 3404 NULL, NULL, 3405 g_cclosure_marshal_VOID__VOID, 3406 G_TYPE_NONE, 0); 3407 3408 et_signals[WHITE_SPACE_EVENT] = g_signal_new ( 3409 "white_space_event", 3410 G_OBJECT_CLASS_TYPE (object_class), 3411 G_SIGNAL_RUN_LAST, 3412 G_STRUCT_OFFSET (ETableClass, white_space_event), 3413 g_signal_accumulator_true_handled, NULL, 3414 e_marshal_BOOLEAN__BOXED, 3415 G_TYPE_BOOLEAN, 1, 3416 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 3417 3418 et_signals[TABLE_DRAG_BEGIN] = g_signal_new ( 3419 "table_drag_begin", 3420 G_OBJECT_CLASS_TYPE (object_class), 3421 G_SIGNAL_RUN_LAST, 3422 G_STRUCT_OFFSET (ETableClass, table_drag_begin), 3423 NULL, NULL, 3424 e_marshal_NONE__INT_INT_OBJECT, 3425 G_TYPE_NONE, 3, 3426 G_TYPE_INT, 3427 G_TYPE_INT, 3428 GDK_TYPE_DRAG_CONTEXT); 3429 3430 et_signals[TABLE_DRAG_END] = g_signal_new ( 3431 "table_drag_end", 3432 G_OBJECT_CLASS_TYPE (object_class), 3433 G_SIGNAL_RUN_LAST, 3434 G_STRUCT_OFFSET (ETableClass, table_drag_end), 3435 NULL, NULL, 3436 e_marshal_NONE__INT_INT_OBJECT, 3437 G_TYPE_NONE, 3, 3438 G_TYPE_INT, 3439 G_TYPE_INT, 3440 GDK_TYPE_DRAG_CONTEXT); 3441 3442 et_signals[TABLE_DRAG_DATA_GET] = g_signal_new ( 3443 "table_drag_data_get", 3444 G_OBJECT_CLASS_TYPE (object_class), 3445 G_SIGNAL_RUN_LAST, 3446 G_STRUCT_OFFSET (ETableClass, table_drag_data_get), 3447 NULL, NULL, 3448 e_marshal_NONE__INT_INT_OBJECT_BOXED_UINT_UINT, 3449 G_TYPE_NONE, 6, 3450 G_TYPE_INT, 3451 G_TYPE_INT, 3452 GDK_TYPE_DRAG_CONTEXT, 3453 GTK_TYPE_SELECTION_DATA | G_SIGNAL_TYPE_STATIC_SCOPE, 3454 G_TYPE_UINT, 3455 G_TYPE_UINT); 3456 3457 et_signals[TABLE_DRAG_DATA_DELETE] = g_signal_new ( 3458 "table_drag_data_delete", 3459 G_OBJECT_CLASS_TYPE (object_class), 3460 G_SIGNAL_RUN_LAST, 3461 G_STRUCT_OFFSET (ETableClass, table_drag_data_delete), 3462 NULL, NULL, 3463 e_marshal_NONE__INT_INT_OBJECT, 3464 G_TYPE_NONE, 3, 3465 G_TYPE_INT, 3466 G_TYPE_INT, 3467 GDK_TYPE_DRAG_CONTEXT); 3468 3469 et_signals[TABLE_DRAG_LEAVE] = g_signal_new ( 3470 "table_drag_leave", 3471 G_OBJECT_CLASS_TYPE (object_class), 3472 G_SIGNAL_RUN_LAST, 3473 G_STRUCT_OFFSET (ETableClass, table_drag_leave), 3474 NULL, NULL, 3475 e_marshal_NONE__INT_INT_OBJECT_UINT, 3476 G_TYPE_NONE, 4, 3477 G_TYPE_INT, 3478 G_TYPE_INT, 3479 GDK_TYPE_DRAG_CONTEXT, 3480 G_TYPE_UINT); 3481 3482 et_signals[TABLE_DRAG_MOTION] = g_signal_new ( 3483 "table_drag_motion", 3484 G_OBJECT_CLASS_TYPE (object_class), 3485 G_SIGNAL_RUN_LAST, 3486 G_STRUCT_OFFSET (ETableClass, table_drag_motion), 3487 NULL, NULL, 3488 e_marshal_BOOLEAN__INT_INT_OBJECT_INT_INT_UINT, 3489 G_TYPE_BOOLEAN, 6, 3490 G_TYPE_INT, 3491 G_TYPE_INT, 3492 GDK_TYPE_DRAG_CONTEXT, 3493 G_TYPE_INT, 3494 G_TYPE_INT, 3495 G_TYPE_UINT); 3496 3497 et_signals[TABLE_DRAG_DROP] = g_signal_new ( 3498 "table_drag_drop", 3499 G_OBJECT_CLASS_TYPE (object_class), 3500 G_SIGNAL_RUN_LAST, 3501 G_STRUCT_OFFSET (ETableClass, table_drag_drop), 3502 NULL, NULL, 3503 e_marshal_BOOLEAN__INT_INT_OBJECT_INT_INT_UINT, 3504 G_TYPE_BOOLEAN, 6, 3505 G_TYPE_INT, 3506 G_TYPE_INT, 3507 GDK_TYPE_DRAG_CONTEXT, 3508 G_TYPE_INT, 3509 G_TYPE_INT, 3510 G_TYPE_UINT); 3511 3512 et_signals[TABLE_DRAG_DATA_RECEIVED] = g_signal_new ( 3513 "table_drag_data_received", 3514 G_OBJECT_CLASS_TYPE (object_class), 3515 G_SIGNAL_RUN_LAST, 3516 G_STRUCT_OFFSET (ETableClass, table_drag_data_received), 3517 NULL, NULL, 3518 e_marshal_NONE__INT_INT_OBJECT_INT_INT_BOXED_UINT_UINT, 3519 G_TYPE_NONE, 8, 3520 G_TYPE_INT, 3521 G_TYPE_INT, 3522 GDK_TYPE_DRAG_CONTEXT, 3523 G_TYPE_INT, 3524 G_TYPE_INT, 3525 GTK_TYPE_SELECTION_DATA | G_SIGNAL_TYPE_STATIC_SCOPE, 3526 G_TYPE_UINT, 3527 G_TYPE_UINT); 3528 3529 g_object_class_install_property ( 3530 object_class, 3531 PROP_LENGTH_THRESHOLD, 3532 g_param_spec_int ( 3533 "length_threshold", 3534 "Length Threshold", 3535 NULL, 3536 0, G_MAXINT, 0, 3537 G_PARAM_WRITABLE)); 3538 3539 g_object_class_install_property ( 3540 object_class, 3541 PROP_UNIFORM_ROW_HEIGHT, 3542 g_param_spec_boolean ( 3543 "uniform_row_height", 3544 "Uniform row height", 3545 NULL, 3546 FALSE, 3547 G_PARAM_READWRITE)); 3548 3549 g_object_class_install_property ( 3550 object_class, 3551 PROP_ALWAYS_SEARCH, 3552 g_param_spec_boolean ( 3553 "always_search", 3554 "Always search", 3555 NULL, 3556 FALSE, 3557 G_PARAM_READWRITE)); 3558 3559 g_object_class_install_property ( 3560 object_class, 3561 PROP_USE_CLICK_TO_ADD, 3562 g_param_spec_boolean ( 3563 "use_click_to_add", 3564 "Use click to add", 3565 NULL, 3566 FALSE, 3567 G_PARAM_READWRITE)); 3568 3569 g_object_class_install_property ( 3570 object_class, 3571 PROP_MODEL, 3572 g_param_spec_object ( 3573 "model", 3574 "Model", 3575 NULL, 3576 E_TYPE_TABLE_MODEL, 3577 G_PARAM_READABLE)); 3578 3579 gtk_widget_class_install_style_property ( 3580 widget_class, 3581 g_param_spec_int ( 3582 "vertical-spacing", 3583 "Vertical Row Spacing", 3584 "Vertical space between rows. " 3585 "It is added to top and to bottom of a row", 3586 0, G_MAXINT, 3, 3587 G_PARAM_READABLE | 3588 G_PARAM_STATIC_STRINGS)); 3589 3590 /* Scrollable interface */ 3591 g_object_class_override_property ( 3592 object_class, PROP_HADJUSTMENT, "hadjustment"); 3593 g_object_class_override_property ( 3594 object_class, PROP_VADJUSTMENT, "vadjustment"); 3595 g_object_class_override_property ( 3596 object_class, PROP_HSCROLL_POLICY, "hscroll-policy"); 3597 g_object_class_override_property ( 3598 object_class, PROP_VSCROLL_POLICY, "vscroll-policy"); 3599 3600 gal_a11y_e_table_init (); 3601 } 3602 3603 void 3604 e_table_freeze_state_change (ETable *table) 3605 { 3606 g_return_if_fail (table != NULL); 3607 3608 table->state_change_freeze++; 3609 if (table->state_change_freeze == 1) 3610 table->state_changed = FALSE; 3611 3612 g_return_if_fail (table->state_change_freeze != 0); 3613 } 3614 3615 void 3616 e_table_thaw_state_change (ETable *table) 3617 { 3618 g_return_if_fail (table != NULL); 3619 g_return_if_fail (table->state_change_freeze != 0); 3620 3621 table->state_change_freeze--; 3622 if (table->state_change_freeze == 0 && table->state_changed) { 3623 table->state_changed = FALSE; 3624 e_table_state_change (table); 3625 } 3626 }