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

Location Tool Test ID Function Issue
e-table-header-item.c:1240:13 clang-analyzer Value stored to 'widget' during its initialization is never read
e-table-header-item.c:1240:13 clang-analyzer Value stored to 'widget' during its initialization is never read
e-table-header-item.c:1956:24 clang-analyzer Assigned value is garbage or undefined
e-table-header-item.c:1956:24 clang-analyzer Assigned value is garbage or undefined
   1 /*
   2  * This program is free software; you can redistribute it and/or
   3  * modify it under the terms of the GNU Lesser General Public
   4  * License as published by the Free Software Foundation; either
   5  * version 2 of the License, or (at your option) version 3.
   6  *
   7  * This program is distributed in the hope that it will be useful,
   8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10  * Lesser General Public License for more details.
  11  *
  12  * You should have received a copy of the GNU Lesser General Public
  13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  14  *
  15  *
  16  * Authors:
  17  *		Chris Lahey <clahey@ximian.com>
  18  *		Miguel de Icaza <miguel@gnu.org>
  19  *
  20  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  21  *
  22  */
  23 
  24 #ifdef HAVE_CONFIG_H
  25 #include <config.h>
  26 #endif
  27 
  28 #include <string.h>
  29 
  30 #include <gtk/gtk.h>
  31 #include <libgnomecanvas/libgnomecanvas.h>
  32 #include <gdk-pixbuf/gdk-pixbuf.h>
  33 #include <gdk/gdkkeysyms.h>
  34 
  35 #include <glib/gi18n.h>
  36 #include "e-util/e-util.h"
  37 #include "libevolution-utils/e-xml-utils.h"
  38 #include "misc/e-canvas.h"
  39 
  40 #include "e-popup-menu.h"
  41 #include "e-table.h"
  42 #include "e-table-col-dnd.h"
  43 #include "e-table-config.h"
  44 #include "e-table-defines.h"
  45 #include "e-table-field-chooser-dialog.h"
  46 #include "e-table-header.h"
  47 #include "e-table-header-utils.h"
  48 
  49 #include "e-table-header-item.h"
  50 
  51 #include "arrow-up.xpm"
  52 #include "arrow-down.xpm"
  53 
  54 enum {
  55 	BUTTON_PRESSED,
  56 	LAST_SIGNAL
  57 };
  58 
  59 static guint ethi_signals[LAST_SIGNAL] = { 0, };
  60 
  61 #define ARROW_DOWN_HEIGHT 16
  62 #define ARROW_PTR          7
  63 
  64 /* Defines the tolerance for proximity of the column division to the cursor position */
  65 #define TOLERANCE 4
  66 
  67 #define ETHI_RESIZING(x) ((x)->resize_col != -1)
  68 
  69 #define ethi_get_type e_table_header_item_get_type
  70 G_DEFINE_TYPE (ETableHeaderItem, ethi, GNOME_TYPE_CANVAS_ITEM)
  71 
  72 #define d(x)
  73 
  74 static void ethi_drop_table_header (ETableHeaderItem *ethi);
  75 
  76 /*
  77  * They display the arrows for the drop location.
  78  */
  79 
  80 static GtkWidget *arrow_up, *arrow_down;
  81 
  82 enum {
  83 	PROP_0,
  84 	PROP_TABLE_HEADER,
  85 	PROP_FULL_HEADER,
  86 	PROP_DND_CODE,
  87 	PROP_TABLE_FONT_DESC,
  88 	PROP_SORT_INFO,
  89 	PROP_TABLE,
  90 	PROP_TREE
  91 };
  92 
  93 enum {
  94 	ET_SCROLL_UP = 1 << 0,
  95 	ET_SCROLL_DOWN = 1 << 1,
  96 	ET_SCROLL_LEFT = 1 << 2,
  97 	ET_SCROLL_RIGHT = 1 << 3
  98 };
  99 
 100 static void scroll_off (ETableHeaderItem *ethi);
 101 static void scroll_on (ETableHeaderItem *ethi, guint scroll_direction);
 102 
 103 static void
 104 ethi_dispose (GObject *object)
 105 {
 106 	ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (object);
 107 
 108 	ethi_drop_table_header (ethi);
 109 
 110 	scroll_off (ethi);
 111 
 112 	if (ethi->resize_cursor) {
 113 		g_object_unref (ethi->resize_cursor);
 114 		ethi->resize_cursor = NULL;
 115 	}
 116 
 117 	if (ethi->dnd_code) {
 118 		g_free (ethi->dnd_code);
 119 		ethi->dnd_code = NULL;
 120 	}
 121 
 122 	if (ethi->sort_info) {
 123 		if (ethi->sort_info_changed_id)
 124 			g_signal_handler_disconnect (
 125 				ethi->sort_info, ethi->sort_info_changed_id);
 126 		if (ethi->group_info_changed_id)
 127 			g_signal_handler_disconnect (
 128 				ethi->sort_info, ethi->group_info_changed_id);
 129 		g_object_unref (ethi->sort_info);
 130 		ethi->sort_info = NULL;
 131 	}
 132 
 133 	if (ethi->full_header)
 134 		g_object_unref (ethi->full_header);
 135 	ethi->full_header = NULL;
 136 
 137 	if (ethi->etfcd.widget)
 138 		g_object_remove_weak_pointer (
 139 			G_OBJECT (ethi->etfcd.widget), &ethi->etfcd.pointer);
 140 
 141 	if (ethi->config)
 142 		g_object_unref (ethi->config);
 143 	ethi->config = NULL;
 144 
 145 	/* Chain up to parent's dispose() method. */
 146 	G_OBJECT_CLASS (ethi_parent_class)->dispose (object);
 147 }
 148 
 149 static gint
 150 e_table_header_item_get_height (ETableHeaderItem *ethi)
 151 {
 152 	ETableHeader *eth;
 153 	gint numcols, col;
 154 	gint maxheight;
 155 
 156 	g_return_val_if_fail (ethi != NULL, 0);
 157 	g_return_val_if_fail (E_IS_TABLE_HEADER_ITEM (ethi), 0);
 158 
 159 	eth = ethi->eth;
 160 	numcols = e_table_header_count (eth);
 161 
 162 	maxheight = 0;
 163 
 164 	for (col = 0; col < numcols; col++) {
 165 		ETableCol *ecol = e_table_header_get_column (eth, col);
 166 		gint height;
 167 
 168 		height = e_table_header_compute_height (
 169 			ecol, GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas));
 170 
 171 		if (height > maxheight)
 172 			maxheight = height;
 173 	}
 174 
 175 	return maxheight;
 176 }
 177 
 178 static void
 179 ethi_update (GnomeCanvasItem *item,
 180              const cairo_matrix_t *i2c,
 181              gint flags)
 182 {
 183 	ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item);
 184 	gdouble x1, y1, x2, y2;
 185 
 186 	if (GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->update)
 187 		GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->update (
 188 			item, i2c, flags);
 189 
 190 	if (ethi->sort_info)
 191 		ethi->group_indent_width =
 192 			e_table_sort_info_grouping_get_count (ethi->sort_info)
 193 			* GROUP_INDENT;
 194 	else
 195 		ethi->group_indent_width = 0;
 196 
 197 	ethi->width =
 198 		e_table_header_total_width (ethi->eth) +
 199 		ethi->group_indent_width;
 200 
 201 	x1 = y1 = 0;
 202 	x2 = ethi->width;
 203 	y2 = ethi->height;
 204 
 205 	gnome_canvas_matrix_transform_rect (i2c, &x1, &y1, &x2, &y2);
 206 
 207 	if (item->x1 != x1 ||
 208 	    item->y1 != y1 ||
 209 	    item->x2 != x2 ||
 210 	    item->y2 != y2) {
 211 		gnome_canvas_request_redraw (
 212 			item->canvas,
 213 			item->x1, item->y1,
 214 			item->x2, item->y2);
 215 		item->x1 = x1;
 216 		item->y1 = y1;
 217 		item->x2 = x2;
 218 		item->y2 = y2;
 219 	}
 220 	gnome_canvas_request_redraw (
 221 		item->canvas, item->x1, item->y1, item->x2, item->y2);
 222 }
 223 
 224 static void
 225 ethi_font_set (ETableHeaderItem *ethi,
 226                PangoFontDescription *font_desc)
 227 {
 228 	if (ethi->font_desc)
 229 		pango_font_description_free (ethi->font_desc);
 230 
 231 	ethi->font_desc = pango_font_description_copy (font_desc);
 232 
 233 	ethi->height = e_table_header_item_get_height (ethi);
 234 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (ethi));
 235 }
 236 
 237 static void
 238 ethi_drop_table_header (ETableHeaderItem *ethi)
 239 {
 240 	GObject *header;
 241 
 242 	if (!ethi->eth)
 243 		return;
 244 
 245 	header = G_OBJECT (ethi->eth);
 246 	g_signal_handler_disconnect (header, ethi->structure_change_id);
 247 	g_signal_handler_disconnect (header, ethi->dimension_change_id);
 248 
 249 	g_object_unref (header);
 250 	ethi->eth = NULL;
 251 	ethi->width = 0;
 252 }
 253 
 254 static void
 255 structure_changed (ETableHeader *header,
 256                    ETableHeaderItem *ethi)
 257 {
 258 	gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ethi));
 259 }
 260 
 261 static void
 262 dimension_changed (ETableHeader *header,
 263                    gint col,
 264                    ETableHeaderItem *ethi)
 265 {
 266 	gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ethi));
 267 }
 268 
 269 static void
 270 ethi_add_table_header (ETableHeaderItem *ethi,
 271                        ETableHeader *header)
 272 {
 273 	ethi->eth = header;
 274 	g_object_ref (ethi->eth);
 275 
 276 	ethi->height = e_table_header_item_get_height (ethi);
 277 
 278 	ethi->structure_change_id = g_signal_connect (
 279 		header, "structure_change",
 280 		G_CALLBACK (structure_changed), ethi);
 281 	ethi->dimension_change_id = g_signal_connect (
 282 		header, "dimension_change",
 283 		G_CALLBACK (dimension_changed), ethi);
 284 	e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (ethi));
 285 	gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ethi));
 286 }
 287 
 288 static void
 289 ethi_sort_info_changed (ETableSortInfo *sort_info,
 290                         ETableHeaderItem *ethi)
 291 {
 292 	gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ethi));
 293 }
 294 
 295 static void
 296 ethi_set_property (GObject *object,
 297                    guint property_id,
 298                    const GValue *value,
 299                    GParamSpec *pspec)
 300 {
 301 	GnomeCanvasItem *item;
 302 	ETableHeaderItem *ethi;
 303 
 304 	item = GNOME_CANVAS_ITEM (object);
 305 	ethi = E_TABLE_HEADER_ITEM (object);
 306 
 307 	switch (property_id) {
 308 	case PROP_TABLE_HEADER:
 309 		ethi_drop_table_header (ethi);
 310 		ethi_add_table_header (ethi, E_TABLE_HEADER (g_value_get_object (value)));
 311 		break;
 312 
 313 	case PROP_FULL_HEADER:
 314 		if (ethi->full_header)
 315 			g_object_unref (ethi->full_header);
 316 		ethi->full_header = E_TABLE_HEADER (g_value_get_object (value));
 317 		if (ethi->full_header)
 318 			g_object_ref (ethi->full_header);
 319 		break;
 320 
 321 	case PROP_DND_CODE:
 322 		g_free (ethi->dnd_code);
 323 		ethi->dnd_code = g_strdup (g_value_get_string (value));
 324 		break;
 325 
 326 	case PROP_TABLE_FONT_DESC:
 327 		ethi_font_set (ethi, g_value_get_boxed (value));
 328 		break;
 329 
 330 	case PROP_SORT_INFO:
 331 		if (ethi->sort_info) {
 332 			if (ethi->sort_info_changed_id)
 333 				g_signal_handler_disconnect (
 334 					ethi->sort_info,
 335 					ethi->sort_info_changed_id);
 336 
 337 			if (ethi->group_info_changed_id)
 338 				g_signal_handler_disconnect (
 339 					ethi->sort_info,
 340 					ethi->group_info_changed_id);
 341 			g_object_unref (ethi->sort_info);
 342 		}
 343 		ethi->sort_info = g_value_get_object (value);
 344 		g_object_ref (ethi->sort_info);
 345 		ethi->sort_info_changed_id =
 346 			g_signal_connect (
 347 				ethi->sort_info, "sort_info_changed",
 348 				G_CALLBACK (ethi_sort_info_changed), ethi);
 349 		ethi->group_info_changed_id =
 350 			g_signal_connect (
 351 				ethi->sort_info, "group_info_changed",
 352 				G_CALLBACK (ethi_sort_info_changed), ethi);
 353 		break;
 354 	case PROP_TABLE:
 355 		if (g_value_get_object (value))
 356 			ethi->table = E_TABLE (g_value_get_object (value));
 357 		else
 358 			ethi->table = NULL;
 359 		break;
 360 	case PROP_TREE:
 361 		if (g_value_get_object (value))
 362 			ethi->tree = E_TREE (g_value_get_object (value));
 363 		else
 364 			ethi->tree = NULL;
 365 		break;
 366 	}
 367 	gnome_canvas_item_request_update (item);
 368 }
 369 
 370 static void
 371 ethi_get_property (GObject *object,
 372                    guint property_id,
 373                    GValue *value,
 374                    GParamSpec *pspec)
 375 {
 376 	ETableHeaderItem *ethi;
 377 
 378 	ethi = E_TABLE_HEADER_ITEM (object);
 379 
 380 	switch (property_id) {
 381 	case PROP_FULL_HEADER:
 382 		g_value_set_object (value, ethi->full_header);
 383 		break;
 384 	case PROP_DND_CODE:
 385 		g_value_set_string (value, ethi->dnd_code);
 386 		break;
 387 	default:
 388 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 389 		break;
 390 	}
 391 }
 392 
 393 static gint
 394 ethi_find_col_by_x (ETableHeaderItem *ethi,
 395                     gint x)
 396 {
 397 	const gint cols = e_table_header_count (ethi->eth);
 398 	gint x1 = 0;
 399 	gint col;
 400 
 401 	d (g_print ("%s:%d: x = %d, x1 = %d\n", __FUNCTION__, __LINE__, x, x1));
 402 
 403 	x1 += ethi->group_indent_width;
 404 
 405 	if (x < x1) {
 406 		d (g_print ("%s:%d: Returning 0\n", __FUNCTION__, __LINE__));
 407 		return 0;
 408 	}
 409 
 410 	for (col = 0; col < cols; col++) {
 411 		ETableCol *ecol = e_table_header_get_column (ethi->eth, col);
 412 
 413 		if ((x >= x1) && (x <= x1 + ecol->width)) {
 414 			d (g_print ("%s:%d: Returning %d\n", __FUNCTION__, __LINE__, col));
 415 			return col;
 416 		}
 417 
 418 		x1 += ecol->width;
 419 	}
 420 	d (g_print ("%s:%d: Returning %d\n", __FUNCTION__, __LINE__, cols - 1));
 421 	return cols - 1;
 422 }
 423 
 424 static gint
 425 ethi_find_col_by_x_nearest (ETableHeaderItem *ethi,
 426                             gint x)
 427 {
 428 	const gint cols = e_table_header_count (ethi->eth);
 429 	gint x1 = 0;
 430 	gint col;
 431 
 432 	x1 += ethi->group_indent_width;
 433 
 434 	if (x < x1)
 435 		return 0;
 436 
 437 	for (col = 0; col < cols; col++) {
 438 		ETableCol *ecol = e_table_header_get_column (ethi->eth, col);
 439 
 440 		x1 += (ecol->width / 2);
 441 
 442 		if (x <= x1)
 443 			return col;
 444 
 445 		x1 += (ecol->width + 1) / 2;
 446 	}
 447 	return col;
 448 }
 449 
 450 static void
 451 ethi_remove_drop_marker (ETableHeaderItem *ethi)
 452 {
 453 	if (ethi->drag_mark == -1)
 454 		return;
 455 
 456 	gtk_widget_hide (arrow_up);
 457 	gtk_widget_hide (arrow_down);
 458 
 459 	ethi->drag_mark = -1;
 460 }
 461 
 462 static GtkWidget *
 463 make_shaped_window_from_xpm (const gchar **xpm)
 464 {
 465 	GdkPixbuf *pixbuf;
 466 	GtkWidget *win, *pix;
 467 
 468 	pixbuf = gdk_pixbuf_new_from_xpm_data (xpm);
 469 
 470 	win = gtk_window_new (GTK_WINDOW_POPUP);
 471 	gtk_window_set_type_hint (GTK_WINDOW (win), GDK_WINDOW_TYPE_HINT_NOTIFICATION);
 472 
 473 	pix = gtk_image_new_from_pixbuf (pixbuf);
 474 	gtk_widget_realize (win);
 475 	gtk_container_add (GTK_CONTAINER (win), pix);
 476 
 477 	g_object_unref (pixbuf);
 478 
 479 	return win;
 480 }
 481 
 482 static void
 483 ethi_add_drop_marker (ETableHeaderItem *ethi,
 484                       gint col,
 485                       gboolean recreate)
 486 {
 487 	GnomeCanvas *canvas;
 488 	GtkAdjustment *adjustment;
 489 	GdkWindow *window;
 490 	gint rx, ry;
 491 	gint x;
 492 
 493 	if (!recreate && ethi->drag_mark == col)
 494 		return;
 495 
 496 	ethi->drag_mark = col;
 497 
 498 	x = e_table_header_col_diff (ethi->eth, 0, col);
 499 	if (col > 0)
 500 		x += ethi->group_indent_width;
 501 
 502 	if (!arrow_up) {
 503 		arrow_up   = make_shaped_window_from_xpm (arrow_up_xpm);
 504 		arrow_down = make_shaped_window_from_xpm (arrow_down_xpm);
 505 	}
 506 
 507 	canvas = GNOME_CANVAS_ITEM (ethi)->canvas;
 508 	window = gtk_widget_get_window (GTK_WIDGET (canvas));
 509 	gdk_window_get_origin (window, &rx, &ry);
 510 
 511 	adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
 512 	rx -= gtk_adjustment_get_value (adjustment);
 513 
 514 	adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
 515 	ry -= gtk_adjustment_get_value (adjustment);
 516 
 517 	gtk_window_move (
 518 		GTK_WINDOW (arrow_down),
 519 		rx + x - ARROW_PTR,
 520 		ry - ARROW_DOWN_HEIGHT);
 521 	gtk_widget_show_all (arrow_down);
 522 
 523 	gtk_window_move (
 524 		GTK_WINDOW (arrow_up),
 525 		rx + x - ARROW_PTR,
 526 		ry + ethi->height);
 527 	gtk_widget_show_all (arrow_up);
 528 }
 529 
 530 static void
 531 ethi_add_destroy_marker (ETableHeaderItem *ethi)
 532 {
 533 	gdouble x1;
 534 
 535 	if (ethi->remove_item)
 536 		g_object_run_dispose (G_OBJECT (ethi->remove_item));
 537 
 538 	x1 = (gdouble) e_table_header_col_diff (ethi->eth, 0, ethi->drag_col);
 539 	if (ethi->drag_col > 0)
 540 		x1 += ethi->group_indent_width;
 541 
 542 	ethi->remove_item = gnome_canvas_item_new (
 543 		GNOME_CANVAS_GROUP (GNOME_CANVAS_ITEM (ethi)->canvas->root),
 544 		gnome_canvas_rect_get_type (),
 545 		"x1", x1 + 1,
 546 		"y1", (gdouble) 1,
 547 		"x2", (gdouble) x1 + e_table_header_col_diff (
 548 			ethi->eth, ethi->drag_col, ethi->drag_col + 1) - 2,
 549 
 550 		"y2", (gdouble) ethi->height - 2,
 551 		"fill_color_rgba", 0xFF000080,
 552 		NULL);
 553 }
 554 
 555 static void
 556 ethi_remove_destroy_marker (ETableHeaderItem *ethi)
 557 {
 558 	if (!ethi->remove_item)
 559 		return;
 560 
 561 	g_object_run_dispose (G_OBJECT (ethi->remove_item));
 562 	ethi->remove_item = NULL;
 563 }
 564 
 565 #if 0
 566 static gboolean
 567 moved (ETableHeaderItem *ethi,
 568        guint col,
 569        guint model_col)
 570 {
 571 	if (col == -1)
 572 		return TRUE;
 573 	ecol = e_table_header_get_column (ethi->eth, col);
 574 	if (ecol->col_idx == model_col)
 575 		return FALSE;
 576 	if (col > 0) {
 577 		ecol = e_table_header_get_column (ethi->eth, col - 1);
 578 		if (ecol->col_idx == model_col)
 579 			return FALSE;
 580 	}
 581 	return TRUE;
 582 }
 583 #endif
 584 
 585 static void
 586 do_drag_motion (ETableHeaderItem *ethi,
 587                 GdkDragContext *context,
 588                 gint x,
 589                 gint y,
 590                 guint time,
 591                 gboolean recreate)
 592 {
 593 	if ((x >= 0) && (x <= (ethi->width)) &&
 594 	    (y >= 0) && (y <= (ethi->height))) {
 595 		GdkDragAction suggested_action;
 596 		gint col;
 597 		d (g_print ("In header\n"));
 598 
 599 		col = ethi_find_col_by_x_nearest (ethi, x);
 600 		suggested_action = gdk_drag_context_get_suggested_action (context);
 601 
 602 		if (ethi->drag_col != -1 && (col == ethi->drag_col ||
 603 		    col == ethi->drag_col + 1)) {
 604 			if (ethi->drag_col != -1)
 605 				ethi_remove_destroy_marker (ethi);
 606 
 607 			ethi_remove_drop_marker (ethi);
 608 			gdk_drag_status (context, suggested_action, time);
 609 		}
 610 		else if (col != -1) {
 611 			if (ethi->drag_col != -1)
 612 				ethi_remove_destroy_marker (ethi);
 613 
 614 			ethi_add_drop_marker (ethi, col, recreate);
 615 			gdk_drag_status (context, suggested_action, time);
 616 		} else {
 617 			ethi_remove_drop_marker (ethi);
 618 			if (ethi->drag_col != -1)
 619 				ethi_add_destroy_marker (ethi);
 620 		}
 621 	} else {
 622 		ethi_remove_drop_marker (ethi);
 623 		if (ethi->drag_col != -1)
 624 			ethi_add_destroy_marker (ethi);
 625 	}
 626 }
 627 
 628 static gboolean
 629 scroll_timeout (gpointer data)
 630 {
 631 	ETableHeaderItem *ethi = data;
 632 	gint dx = 0;
 633 	GtkAdjustment *adjustment;
 634 	GtkScrollable *scrollable;
 635 	gdouble hadjustment_value;
 636 	gdouble vadjustment_value;
 637 	gdouble page_size;
 638 	gdouble lower;
 639 	gdouble upper;
 640 	gdouble value;
 641 
 642 	if (ethi->scroll_direction & ET_SCROLL_RIGHT)
 643 		dx += 20;
 644 	if (ethi->scroll_direction & ET_SCROLL_LEFT)
 645 		dx -= 20;
 646 
 647 	scrollable = GTK_SCROLLABLE (GNOME_CANVAS_ITEM (ethi)->canvas);
 648 
 649 	adjustment = gtk_scrollable_get_hadjustment (scrollable);
 650 	hadjustment_value = gtk_adjustment_get_value (adjustment);
 651 
 652 	adjustment = gtk_scrollable_get_vadjustment (scrollable);
 653 	vadjustment_value = gtk_adjustment_get_value (adjustment);
 654 
 655 	value = hadjustment_value;
 656 
 657 	adjustment = gtk_scrollable_get_hadjustment (scrollable);
 658 	page_size = gtk_adjustment_get_page_size (adjustment);
 659 	lower = gtk_adjustment_get_lower (adjustment);
 660 	upper = gtk_adjustment_get_upper (adjustment);
 661 
 662 	gtk_adjustment_set_value (
 663 		adjustment, CLAMP (
 664 		hadjustment_value + dx, lower, upper - page_size));
 665 
 666 	hadjustment_value = gtk_adjustment_get_value (adjustment);
 667 
 668 	if (hadjustment_value != value)
 669 		do_drag_motion (
 670 			ethi,
 671 			ethi->last_drop_context,
 672 			ethi->last_drop_x + hadjustment_value,
 673 			ethi->last_drop_y + vadjustment_value,
 674 			ethi->last_drop_time,
 675 			TRUE);
 676 
 677 	return TRUE;
 678 }
 679 
 680 static void
 681 scroll_on (ETableHeaderItem *ethi,
 682            guint scroll_direction)
 683 {
 684 	if (ethi->scroll_idle_id == 0 || scroll_direction != ethi->scroll_direction) {
 685 		if (ethi->scroll_idle_id != 0)
 686 			g_source_remove (ethi->scroll_idle_id);
 687 		ethi->scroll_direction = scroll_direction;
 688 		ethi->scroll_idle_id = g_timeout_add (100, scroll_timeout, ethi);
 689 	}
 690 }
 691 
 692 static void
 693 scroll_off (ETableHeaderItem *ethi)
 694 {
 695 	if (ethi->scroll_idle_id) {
 696 		g_source_remove (ethi->scroll_idle_id);
 697 		ethi->scroll_idle_id = 0;
 698 	}
 699 }
 700 
 701 static void
 702 context_destroyed (gpointer data)
 703 {
 704 	ETableHeaderItem *ethi = data;
 705 
 706 	ethi->last_drop_x       = 0;
 707 	ethi->last_drop_y       = 0;
 708 	ethi->last_drop_time    = 0;
 709 	ethi->last_drop_context = NULL;
 710 	scroll_off (ethi);
 711 
 712 	g_object_unref (ethi);
 713 }
 714 
 715 static void
 716 context_connect (ETableHeaderItem *ethi,
 717                  GdkDragContext *context)
 718 {
 719 	if (g_dataset_get_data (context, "e-table-header-item") == NULL)
 720 		g_dataset_set_data_full (
 721 			context, "e-table-header-item",
 722 			g_object_ref (ethi), context_destroyed);
 723 }
 724 
 725 static gboolean
 726 ethi_drag_motion (GtkWidget *widget,
 727                   GdkDragContext *context,
 728                   gint x,
 729                   gint y,
 730                   guint time,
 731                   ETableHeaderItem *ethi)
 732 {
 733 	GtkAllocation allocation;
 734 	GtkAdjustment *adjustment;
 735 	GList *targets;
 736 	gdouble hadjustment_value;
 737 	gdouble vadjustment_value;
 738 	gchar *droptype, *headertype;
 739 	guint direction = 0;
 740 
 741 	gdk_drag_status (context, 0, time);
 742 
 743 	targets = gdk_drag_context_list_targets (context);
 744 	droptype = gdk_atom_name (GDK_POINTER_TO_ATOM (targets->data));
 745 	headertype = g_strdup_printf (
 746 		"%s-%s", TARGET_ETABLE_COL_TYPE, ethi->dnd_code);
 747 
 748 	if (strcmp (droptype, headertype) != 0) {
 749 		g_free (headertype);
 750 		return FALSE;
 751 	}
 752 
 753 	g_free (headertype);
 754 
 755 	gtk_widget_get_allocation (widget, &allocation);
 756 
 757 	if (x < 20)
 758 		direction |= ET_SCROLL_LEFT;
 759 	if (x > allocation.width - 20)
 760 		direction |= ET_SCROLL_RIGHT;
 761 
 762 	ethi->last_drop_x = x;
 763 	ethi->last_drop_y = y;
 764 	ethi->last_drop_time = time;
 765 	ethi->last_drop_context = context;
 766 	context_connect (ethi, context);
 767 
 768 	adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (widget));
 769 	hadjustment_value = gtk_adjustment_get_value (adjustment);
 770 
 771 	adjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (widget));
 772 	vadjustment_value = gtk_adjustment_get_value (adjustment);
 773 
 774 	do_drag_motion (
 775 		ethi, context,
 776 		x + hadjustment_value,
 777 		y + vadjustment_value,
 778 		time, FALSE);
 779 
 780 	if (direction != 0)
 781 		scroll_on (ethi, direction);
 782 	else
 783 		scroll_off (ethi);
 784 
 785 	return TRUE;
 786 }
 787 
 788 static void
 789 ethi_drag_end (GtkWidget *canvas,
 790                GdkDragContext *context,
 791                ETableHeaderItem *ethi)
 792 {
 793 	ethi_remove_drop_marker (ethi);
 794 	ethi_remove_destroy_marker (ethi);
 795 	ethi->drag_col = -1;
 796 	scroll_off (ethi);
 797 }
 798 
 799 static void
 800 ethi_drag_data_received (GtkWidget *canvas,
 801                          GdkDragContext *drag_context,
 802                          gint x,
 803                          gint y,
 804                          GtkSelectionData *selection_data,
 805                          guint info,
 806                          guint time,
 807                          ETableHeaderItem *ethi)
 808 {
 809 	const guchar *data;
 810 	gint found = FALSE;
 811 	gint count;
 812 	gint column;
 813 	gint drop_col;
 814 	gint i;
 815 
 816 	data = gtk_selection_data_get_data (selection_data);
 817 
 818 	if (data != NULL) {
 819 		count = e_table_header_count (ethi->eth);
 820 		column = atoi ((gchar *) data);
 821 		drop_col = ethi->drop_col;
 822 		ethi->drop_col = -1;
 823 
 824 		if (column >= 0) {
 825 			for (i = 0; i < count; i++) {
 826 				ETableCol *ecol = e_table_header_get_column (ethi->eth, i);
 827 				if (ecol->col_idx == column) {
 828 					e_table_header_move (ethi->eth, i, drop_col);
 829 					found = TRUE;
 830 					break;
 831 				}
 832 			}
 833 			if (!found) {
 834 				count = e_table_header_count (ethi->full_header);
 835 				for (i = 0; i < count; i++) {
 836 					ETableCol *ecol;
 837 
 838 					ecol  = e_table_header_get_column (
 839 						ethi->full_header, i);
 840 
 841 					if (ecol->col_idx == column) {
 842 						e_table_header_add_column (
 843 							ethi->eth, ecol,
 844 							drop_col);
 845 						break;
 846 					}
 847 				}
 848 			}
 849 		}
 850 	}
 851 	ethi_remove_drop_marker (ethi);
 852 	gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ethi));
 853 }
 854 
 855 static void
 856 ethi_drag_data_get (GtkWidget *canvas,
 857                     GdkDragContext *context,
 858                     GtkSelectionData *selection_data,
 859                     guint info,
 860                     guint time,
 861                     ETableHeaderItem *ethi)
 862 {
 863 	if (ethi->drag_col != -1) {
 864 		ETableCol *ecol = e_table_header_get_column (ethi->eth, ethi->drag_col);
 865 
 866 		gchar *string = g_strdup_printf ("%d", ecol->col_idx);
 867 		gtk_selection_data_set (
 868 			selection_data,
 869 			GDK_SELECTION_TYPE_STRING,
 870 			sizeof (string[0]),
 871 			(guchar *) string,
 872 			strlen (string));
 873 		g_free (string);
 874 	}
 875 }
 876 
 877 static gboolean
 878 ethi_drag_drop (GtkWidget *canvas,
 879                 GdkDragContext *context,
 880                 gint x,
 881                 gint y,
 882                 guint time,
 883                 ETableHeaderItem *ethi)
 884 {
 885 	gboolean successful = FALSE;
 886 
 887 	if ((x >= 0) && (x <= (ethi->width)) &&
 888 	    (y >= 0) && (y <= (ethi->height))) {
 889 		gint col;
 890 
 891 		col = ethi_find_col_by_x_nearest (ethi, x);
 892 
 893 		ethi_add_drop_marker (ethi, col, FALSE);
 894 
 895 		ethi->drop_col = col;
 896 
 897 		if (col != -1) {
 898 			gchar *target = g_strdup_printf (
 899 				"%s-%s", TARGET_ETABLE_COL_TYPE, ethi->dnd_code);
 900 			d (g_print ("ethi -  %s\n", target));
 901 			gtk_drag_get_data (
 902 				canvas, context,
 903 				gdk_atom_intern (target, FALSE),
 904 				time);
 905 			g_free (target);
 906 		}
 907 	}
 908 	gtk_drag_finish (context, successful, successful, time);
 909 	scroll_off (ethi);
 910 	return successful;
 911 }
 912 
 913 static void
 914 ethi_drag_leave (GtkWidget *widget,
 915                  GdkDragContext *context,
 916                  guint time,
 917                  ETableHeaderItem *ethi)
 918 {
 919 	ethi_remove_drop_marker (ethi);
 920 	if (ethi->drag_col != -1)
 921 		ethi_add_destroy_marker (ethi);
 922 }
 923 
 924 static void
 925 ethi_realize (GnomeCanvasItem *item)
 926 {
 927 	ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item);
 928 	GtkStyle *style;
 929 	GtkTargetEntry  ethi_drop_types[] = {
 930 		{ (gchar *) TARGET_ETABLE_COL_TYPE, 0, TARGET_ETABLE_COL_HEADER },
 931 	};
 932 
 933 	if (GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)-> realize)
 934 		(*GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->realize)(item);
 935 
 936 	style = gtk_widget_get_style (GTK_WIDGET (item->canvas));
 937 
 938 	if (!ethi->font_desc)
 939 		ethi_font_set (ethi, style->font_desc);
 940 
 941 	/*
 942 	 * Now, configure DnD
 943 	 */
 944 	ethi_drop_types[0].target = g_strdup_printf (
 945 		"%s-%s", ethi_drop_types[0].target, ethi->dnd_code);
 946 	gtk_drag_dest_set (
 947 		GTK_WIDGET (item->canvas), 0, ethi_drop_types,
 948 		G_N_ELEMENTS (ethi_drop_types), GDK_ACTION_MOVE);
 949 	g_free ((gpointer) ethi_drop_types[0].target);
 950 
 951 	/* Drop signals */
 952 	ethi->drag_motion_id = g_signal_connect (
 953 		item->canvas, "drag_motion",
 954 		G_CALLBACK (ethi_drag_motion), ethi);
 955 	ethi->drag_leave_id = g_signal_connect (
 956 		item->canvas, "drag_leave",
 957 		G_CALLBACK (ethi_drag_leave), ethi);
 958 	ethi->drag_drop_id = g_signal_connect (
 959 		item->canvas, "drag_drop",
 960 		G_CALLBACK (ethi_drag_drop), ethi);
 961 	ethi->drag_data_received_id = g_signal_connect (
 962 		item->canvas, "drag_data_received",
 963 		G_CALLBACK (ethi_drag_data_received), ethi);
 964 
 965 	/* Drag signals */
 966 	ethi->drag_end_id = g_signal_connect (
 967 		item->canvas, "drag_end",
 968 		G_CALLBACK (ethi_drag_end), ethi);
 969 	ethi->drag_data_get_id = g_signal_connect (
 970 		item->canvas, "drag_data_get",
 971 		G_CALLBACK (ethi_drag_data_get), ethi);
 972 
 973 }
 974 
 975 static void
 976 ethi_unrealize (GnomeCanvasItem *item)
 977 {
 978 	ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item);
 979 
 980 	if (ethi->font_desc != NULL) {
 981 		pango_font_description_free (ethi->font_desc);
 982 		ethi->font_desc = NULL;
 983 	}
 984 
 985 	g_signal_handler_disconnect (item->canvas, ethi->drag_motion_id);
 986 	g_signal_handler_disconnect (item->canvas, ethi->drag_leave_id);
 987 	g_signal_handler_disconnect (item->canvas, ethi->drag_drop_id);
 988 	g_signal_handler_disconnect (item->canvas, ethi->drag_data_received_id);
 989 
 990 	g_signal_handler_disconnect (item->canvas, ethi->drag_end_id);
 991 	g_signal_handler_disconnect (item->canvas, ethi->drag_data_get_id);
 992 
 993 	gtk_drag_dest_unset (GTK_WIDGET (item->canvas));
 994 
 995 	if (GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->unrealize)
 996 		(*GNOME_CANVAS_ITEM_CLASS (ethi_parent_class)->unrealize)(item);
 997 }
 998 
 999 static void
1000 ethi_draw (GnomeCanvasItem *item,
1001            cairo_t *cr,
1002            gint x,
1003            gint y,
1004            gint width,
1005            gint height)
1006 {
1007 	ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item);
1008 	GnomeCanvas *canvas = item->canvas;
1009 	const gint cols = e_table_header_count (ethi->eth);
1010 	gint x1, x2;
1011 	gint col;
1012 	GHashTable *arrows = g_hash_table_new (NULL, NULL);
1013 	GtkStyleContext *context;
1014 
1015 	if (ethi->sort_info) {
1016 		gint length;
1017 		gint i;
1018 
1019 		length = e_table_sort_info_grouping_get_count (ethi->sort_info);
1020 		for (i = 0; i < length; i++) {
1021 			ETableSortColumn column;
1022 
1023 			column = e_table_sort_info_grouping_get_nth (
1024 				ethi->sort_info, i);
1025 
1026 			g_hash_table_insert (
1027 				arrows,
1028 				GINT_TO_POINTER ((gint) column.column),
1029 				GINT_TO_POINTER (
1030 					column.ascending ?
1031 					E_TABLE_COL_ARROW_DOWN :
1032 					E_TABLE_COL_ARROW_UP));
1033 		}
1034 
1035 		length = e_table_sort_info_sorting_get_count (ethi->sort_info);
1036 		for (i = 0; i < length; i++) {
1037 			ETableSortColumn column;
1038 
1039 			column = e_table_sort_info_sorting_get_nth (
1040 				ethi->sort_info, i);
1041 
1042 			g_hash_table_insert (
1043 				arrows,
1044 				GINT_TO_POINTER ((gint) column.column),
1045 				GINT_TO_POINTER (
1046 					column.ascending ?
1047 					E_TABLE_COL_ARROW_DOWN :
1048 					E_TABLE_COL_ARROW_UP));
1049 		}
1050 	}
1051 
1052 	ethi->width = e_table_header_total_width (ethi->eth) + ethi->group_indent_width;
1053 	x1 = x2 = 0;
1054 	x2 += ethi->group_indent_width;
1055 
1056 	context = gtk_widget_get_style_context (GTK_WIDGET (canvas));
1057 
1058 	for (col = 0; col < cols; col++, x1 = x2) {
1059 		ETableCol *ecol = e_table_header_get_column (ethi->eth, col);
1060 		gint col_width;
1061 		GtkRegionFlags flags = 0;
1062 
1063 		col_width = ecol->width;
1064 
1065 		x2 += col_width;
1066 
1067 		if (x1 > (x + width))
1068 			break;
1069 
1070 		if (x2 < x)
1071 			continue;
1072 
1073 		if (x2 <= x1)
1074 			continue;
1075 
1076 		if (((col + 1) % 2) == 0)
1077 			flags |= GTK_REGION_EVEN;
1078 		else
1079 			flags |= GTK_REGION_ODD;
1080 
1081 		if (col == 0)
1082 			flags |= GTK_REGION_FIRST;
1083 
1084 		if (col + 1 == cols)
1085 			flags |= GTK_REGION_LAST;
1086 
1087 		gtk_style_context_save (context);
1088 		gtk_style_context_add_region (
1089 			context, GTK_STYLE_REGION_COLUMN_HEADER, flags);
1090 
1091 		e_table_header_draw_button (
1092 			cr, ecol, GTK_WIDGET (canvas),
1093 			x1 - x, -y, width, height,
1094 			x2 - x1, ethi->height,
1095 			(ETableColArrow) g_hash_table_lookup (
1096 			arrows, GINT_TO_POINTER (ecol->col_idx)));
1097 
1098 		gtk_style_context_restore (context);
1099 	}
1100 
1101 	g_hash_table_destroy (arrows);
1102 }
1103 
1104 static GnomeCanvasItem *
1105 ethi_point (GnomeCanvasItem *item,
1106             gdouble x,
1107             gdouble y,
1108             gint cx,
1109             gint cy)
1110 {
1111 	return item;
1112 }
1113 
1114 /*
1115  * is_pointer_on_division:
1116  *
1117  * Returns whether @pos is a column header division;  If @the_total is not NULL,
1118  * then the actual position is returned here.  If @return_ecol is not NULL,
1119  * then the ETableCol that actually contains this point is returned here
1120  */
1121 static gboolean
1122 is_pointer_on_division (ETableHeaderItem *ethi,
1123                         gint pos,
1124                         gint *the_total,
1125                         gint *return_col)
1126 {
1127 	const gint cols = e_table_header_count (ethi->eth);
1128 	gint col, total;
1129 
1130 	total = 0;
1131 	for (col = 0; col < cols; col++) {
1132 		ETableCol *ecol = e_table_header_get_column (ethi->eth, col);
1133 
1134 		if (col == 0)
1135 			total += ethi->group_indent_width;
1136 
1137 		total += ecol->width;
1138 
1139 		if ((total - TOLERANCE < pos) && (pos < total + TOLERANCE)) {
1140 			if (return_col)
1141 				*return_col = col;
1142 			if (the_total)
1143 				*the_total = total;
1144 
1145 			return TRUE;
1146 		}
1147 		if (return_col)
1148 			*return_col = col;
1149 
1150 		if (total > pos + TOLERANCE)
1151 			return FALSE;
1152 	}
1153 
1154 	return FALSE;
1155 }
1156 
1157 #define convert(c,sx,sy,x,y) gnome_canvas_w2c (c,sx,sy,x,y)
1158 
1159 static void
1160 set_cursor (ETableHeaderItem *ethi,
1161             gint pos)
1162 {
1163 	GnomeCanvas *canvas;
1164 	GdkWindow *window;
1165 	gboolean resizable = FALSE;
1166 	gint col;
1167 
1168 	canvas = GNOME_CANVAS_ITEM (ethi)->canvas;
1169 	window = gtk_widget_get_window (GTK_WIDGET (canvas));
1170 
1171 	/* We might be invoked before we are realized */
1172 	if (window == NULL)
1173 		return;
1174 
1175 	if (is_pointer_on_division (ethi, pos, NULL, &col)) {
1176 		gint last_col = ethi->eth->col_count - 1;
1177 		ETableCol *ecol = e_table_header_get_column (ethi->eth, col);
1178 
1179 		/* Last column is not resizable */
1180 		if (ecol->resizable && col != last_col) {
1181 			gint c = col + 1;
1182 
1183 			/* Column is not resizable if all columns after it
1184 			 * are also not resizable */
1185 			for (; c <= last_col; c++) {
1186 				ETableCol *ecol2;
1187 
1188 				ecol2 = e_table_header_get_column (ethi->eth, c);
1189 				if (ecol2->resizable) {
1190 					resizable = TRUE;
1191 					break;
1192 				}
1193 			}
1194 		}
1195 	}
1196 
1197 	if (resizable)
1198 		gdk_window_set_cursor (window, ethi->resize_cursor);
1199 	else
1200 		gdk_window_set_cursor (window, NULL);
1201 }
1202 
1203 static void
1204 ethi_end_resize (ETableHeaderItem *ethi)
1205 {
1206 	ethi->resize_col = -1;
1207 	ethi->resize_guide = GINT_TO_POINTER (0);
1208 
1209 	if (ethi->table)
1210 		e_table_thaw_state_change (ethi->table);
1211 	else if (ethi->tree)
1212 		e_tree_thaw_state_change (ethi->tree);
1213 
1214 	gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ethi));
1215 }
1216 
1217 static gboolean
1218 ethi_maybe_start_drag (ETableHeaderItem *ethi,
1219                        GdkEventMotion *event)
1220 {
1221 	if (!ethi->maybe_drag)
1222 		return FALSE;
1223 
1224 	if (ethi->eth->col_count < 2) {
1225 		ethi->maybe_drag = FALSE;
1226 		return FALSE;
1227 	}
1228 
1229 	if (MAX (abs (ethi->click_x - event->x),
1230 		 abs (ethi->click_y - event->y)) <= 3)
1231 		return FALSE;
1232 
1233 	return TRUE;
1234 }
1235 
1236 static void
1237 ethi_start_drag (ETableHeaderItem *ethi,
1238                  GdkEvent *event)
1239 {
1240 	GtkWidget *widget = GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas);
Value stored to 'widget' during its initialization is never read
(emitted by clang-analyzer)

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

Value stored to 'widget' during its initialization is never read
(emitted by clang-analyzer)

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

1241 GtkTargetList *list; 1242 GdkDragContext *context; 1243 ETableCol *ecol; 1244 gint col_width; 1245 cairo_surface_t *s; 1246 cairo_t *cr; 1247 1248 gint group_indent = 0; 1249 GHashTable *arrows = g_hash_table_new (NULL, NULL); 1250 1251 GtkTargetEntry ethi_drag_types[] = { 1252 { (gchar *) TARGET_ETABLE_COL_TYPE, 0, TARGET_ETABLE_COL_HEADER }, 1253 }; 1254 1255 widget = GTK_WIDGET (GNOME_CANVAS_ITEM (ethi)->canvas); 1256 ethi->drag_col = ethi_find_col_by_x (ethi, event->motion.x); 1257 1258 if (ethi->drag_col == -1) 1259 return; 1260 1261 if (ethi->sort_info) { 1262 gint length = e_table_sort_info_grouping_get_count (ethi->sort_info); 1263 gint i; 1264 for (i = 0; i < length; i++) { 1265 ETableSortColumn column = 1266 e_table_sort_info_grouping_get_nth ( 1267 ethi->sort_info, i); 1268 group_indent++; 1269 g_hash_table_insert ( 1270 arrows, 1271 GINT_TO_POINTER ((gint) column.column), 1272 GINT_TO_POINTER ( 1273 column.ascending ? 1274 E_TABLE_COL_ARROW_DOWN : 1275 E_TABLE_COL_ARROW_UP)); 1276 } 1277 length = e_table_sort_info_sorting_get_count (ethi->sort_info); 1278 for (i = 0; i < length; i++) { 1279 ETableSortColumn column = 1280 e_table_sort_info_sorting_get_nth ( 1281 ethi->sort_info, i); 1282 1283 g_hash_table_insert ( 1284 arrows, 1285 GINT_TO_POINTER ((gint) column.column), 1286 GINT_TO_POINTER ( 1287 column.ascending ? 1288 E_TABLE_COL_ARROW_DOWN : 1289 E_TABLE_COL_ARROW_UP)); 1290 } 1291 } 1292 1293 ethi_drag_types[0].target = g_strdup_printf ( 1294 "%s-%s", ethi_drag_types[0].target, ethi->dnd_code); 1295 list = gtk_target_list_new ( 1296 ethi_drag_types, G_N_ELEMENTS (ethi_drag_types)); 1297 context = gtk_drag_begin (widget, list, GDK_ACTION_MOVE, 1, event); 1298 g_free ((gpointer) ethi_drag_types[0].target); 1299 1300 ecol = e_table_header_get_column (ethi->eth, ethi->drag_col); 1301 col_width = ecol->width; 1302 s = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, col_width, ethi->height); 1303 cr = cairo_create (s); 1304 1305 e_table_header_draw_button ( 1306 cr, ecol, 1307 widget, 0, 0, 1308 col_width, ethi->height, 1309 col_width, ethi->height, 1310 (ETableColArrow) g_hash_table_lookup ( 1311 arrows, GINT_TO_POINTER (ecol->col_idx))); 1312 gtk_drag_set_icon_surface (context, s); 1313 cairo_surface_destroy (s); 1314 1315 ethi->maybe_drag = FALSE; 1316 g_hash_table_destroy (arrows); 1317 } 1318 1319 typedef struct { 1320 ETableHeaderItem *ethi; 1321 gint col; 1322 } EthiHeaderInfo; 1323 1324 static void 1325 ethi_popup_sort_ascending (GtkWidget *widget, 1326 EthiHeaderInfo *info) 1327 { 1328 ETableCol *col; 1329 gint model_col = -1; 1330 gint length; 1331 gint i; 1332 gint found = FALSE; 1333 ETableHeaderItem *ethi = info->ethi; 1334 1335 col = e_table_header_get_column (ethi->eth, info->col); 1336 if (col->sortable) 1337 model_col = col->col_idx; 1338 1339 length = e_table_sort_info_grouping_get_count (ethi->sort_info); 1340 for (i = 0; i < length; i++) { 1341 ETableSortColumn column = e_table_sort_info_grouping_get_nth ( 1342 ethi->sort_info, i); 1343 1344 if (model_col == column.column) { 1345 column.ascending = 1; 1346 e_table_sort_info_grouping_set_nth ( 1347 ethi->sort_info, i, column); 1348 found = 1; 1349 break; 1350 } 1351 } 1352 if (!found) { 1353 length = e_table_sort_info_sorting_get_count ( 1354 ethi->sort_info); 1355 for (i = 0; i < length; i++) { 1356 ETableSortColumn column = 1357 e_table_sort_info_sorting_get_nth ( 1358 ethi->sort_info, i); 1359 if (model_col == column.column || model_col == -1) { 1360 column.ascending = 1; 1361 e_table_sort_info_sorting_set_nth ( 1362 ethi->sort_info, i, column); 1363 found = 1; 1364 if (model_col != -1) 1365 break; 1366 } 1367 } 1368 } 1369 if (!found) { 1370 ETableSortColumn column; 1371 column.column = model_col; 1372 column.ascending = 1; 1373 length = e_table_sort_info_sorting_get_count (ethi->sort_info); 1374 if (length == 0) 1375 length++; 1376 e_table_sort_info_sorting_set_nth (ethi->sort_info, length - 1, column); 1377 } 1378 } 1379 1380 static void 1381 ethi_popup_sort_descending (GtkWidget *widget, 1382 EthiHeaderInfo *info) 1383 { 1384 ETableCol *col; 1385 gint model_col=-1; 1386 gint length; 1387 gint i; 1388 gint found = FALSE; 1389 ETableHeaderItem *ethi = info->ethi; 1390 1391 col = e_table_header_get_column (ethi->eth, info->col); 1392 if (col->sortable) 1393 model_col = col->col_idx; 1394 1395 length = e_table_sort_info_grouping_get_count (ethi->sort_info); 1396 for (i = 0; i < length; i++) { 1397 ETableSortColumn column = e_table_sort_info_grouping_get_nth ( 1398 ethi->sort_info, i); 1399 if (model_col == column.column) { 1400 column.ascending = 0; 1401 e_table_sort_info_grouping_set_nth ( 1402 ethi->sort_info, i, column); 1403 found = 1; 1404 break; 1405 } 1406 } 1407 if (!found) { 1408 length = e_table_sort_info_sorting_get_count (ethi->sort_info); 1409 for (i = 0; i < length; i++) { 1410 ETableSortColumn column = 1411 e_table_sort_info_sorting_get_nth ( 1412 ethi->sort_info, i); 1413 1414 if (model_col == column.column || model_col == -1) { 1415 column.ascending = 0; 1416 e_table_sort_info_sorting_set_nth ( 1417 ethi->sort_info, i, column); 1418 found = 1; 1419 if (model_col != -1) 1420 break; 1421 } 1422 } 1423 } 1424 if (!found) { 1425 ETableSortColumn column; 1426 column.column = model_col; 1427 column.ascending = 0; 1428 length = e_table_sort_info_sorting_get_count (ethi->sort_info); 1429 if (length == 0) 1430 length++; 1431 e_table_sort_info_sorting_set_nth ( 1432 ethi->sort_info, length - 1, column); 1433 } 1434 } 1435 1436 static void 1437 ethi_popup_unsort (GtkWidget *widget, 1438 EthiHeaderInfo *info) 1439 { 1440 ETableHeaderItem *ethi = info->ethi; 1441 1442 e_table_sort_info_grouping_truncate (ethi->sort_info, 0); 1443 e_table_sort_info_sorting_truncate (ethi->sort_info, 0); 1444 } 1445 1446 static void 1447 ethi_popup_group_field (GtkWidget *widget, 1448 EthiHeaderInfo *info) 1449 { 1450 ETableCol *col; 1451 gint model_col; 1452 ETableHeaderItem *ethi = info->ethi; 1453 ETableSortColumn column; 1454 1455 col = e_table_header_get_column (ethi->eth, info->col); 1456 model_col = col->col_idx; 1457 1458 column.column = model_col; 1459 column.ascending = 1; 1460 e_table_sort_info_grouping_set_nth (ethi->sort_info, 0, column); 1461 e_table_sort_info_grouping_truncate (ethi->sort_info, 1); 1462 } 1463 1464 static void 1465 ethi_popup_group_box (GtkWidget *widget, 1466 EthiHeaderInfo *info) 1467 { 1468 } 1469 1470 static void 1471 ethi_popup_remove_column (GtkWidget *widget, 1472 EthiHeaderInfo *info) 1473 { 1474 e_table_header_remove (info->ethi->eth, info->col); 1475 } 1476 1477 static void 1478 ethi_popup_field_chooser (GtkWidget *widget, 1479 EthiHeaderInfo *info) 1480 { 1481 GtkWidget *etfcd = info->ethi->etfcd.widget; 1482 1483 if (etfcd) { 1484 gtk_window_present (GTK_WINDOW (etfcd)); 1485 1486 return; 1487 } 1488 1489 info->ethi->etfcd.widget = e_table_field_chooser_dialog_new (); 1490 etfcd = info->ethi->etfcd.widget; 1491 1492 g_object_add_weak_pointer (G_OBJECT (etfcd), &info->ethi->etfcd.pointer); 1493 1494 g_object_set ( 1495 info->ethi->etfcd.widget, 1496 "full_header", info->ethi->full_header, 1497 "header", info->ethi->eth, 1498 "dnd_code", info->ethi->dnd_code, 1499 NULL); 1500 1501 gtk_widget_show (etfcd); 1502 } 1503 1504 static void 1505 ethi_popup_alignment (GtkWidget *widget, 1506 EthiHeaderInfo *info) 1507 { 1508 } 1509 1510 static void 1511 ethi_popup_best_fit (GtkWidget *widget, 1512 EthiHeaderInfo *info) 1513 { 1514 ETableHeaderItem *ethi = info->ethi; 1515 gint width; 1516 1517 g_signal_emit_by_name ( 1518 ethi->eth, 1519 "request_width", 1520 info->col, &width); 1521 /* Add 10 to stop it from "..."ing */ 1522 e_table_header_set_size (ethi->eth, info->col, width + 10); 1523 1524 gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ethi)); 1525 1526 } 1527 1528 static void 1529 ethi_popup_format_columns (GtkWidget *widget, 1530 EthiHeaderInfo *info) 1531 { 1532 } 1533 1534 static void 1535 config_destroyed (gpointer data, 1536 GObject *where_object_was) 1537 { 1538 ETableHeaderItem *ethi = data; 1539 ethi->config = NULL; 1540 } 1541 1542 static void 1543 apply_changes (ETableConfig *config, 1544 ETableHeaderItem *ethi) 1545 { 1546 gchar *state = e_table_state_save_to_string (config->state); 1547 1548 if (ethi->table) 1549 e_table_set_state (ethi->table, state); 1550 if (ethi->tree) 1551 e_tree_set_state (ethi->tree, state); 1552 g_free (state); 1553 1554 gtk_dialog_set_response_sensitive ( 1555 GTK_DIALOG (config->dialog_toplevel), 1556 GTK_RESPONSE_APPLY, FALSE); 1557 } 1558 1559 static void 1560 ethi_popup_customize_view (GtkWidget *widget, 1561 EthiHeaderInfo *info) 1562 { 1563 ETableHeaderItem *ethi = info->ethi; 1564 ETableState *state; 1565 ETableSpecification *spec; 1566 1567 if (ethi->config) 1568 e_table_config_raise (E_TABLE_CONFIG (ethi->config)); 1569 else { 1570 if (ethi->table) { 1571 state = e_table_get_state_object (ethi->table); 1572 spec = ethi->table->spec; 1573 } else if (ethi->tree) { 1574 state = e_tree_get_state_object (ethi->tree); 1575 spec = e_tree_get_spec (ethi->tree); 1576 } else 1577 return; 1578 1579 ethi->config = e_table_config_new ( 1580 _("Customize Current View"), 1581 spec, state, GTK_WINDOW (gtk_widget_get_toplevel (widget))); 1582 g_object_weak_ref ( 1583 G_OBJECT (ethi->config), 1584 config_destroyed, ethi); 1585 g_signal_connect ( 1586 ethi->config, "changed", 1587 G_CALLBACK (apply_changes), ethi); 1588 } 1589 } 1590 1591 static void 1592 free_popup_info (GtkWidget *w, 1593 EthiHeaderInfo *info) 1594 { 1595 g_free (info); 1596 } 1597 1598 /* Bit 1 is always disabled. */ 1599 /* Bit 2 is disabled if not "sortable". */ 1600 /* Bit 4 is disabled if we don't have a pointer to our table object. */ 1601 static EPopupMenu ethi_context_menu[] = { 1602 E_POPUP_ITEM ( 1603 N_("Sort _Ascending"), 1604 G_CALLBACK (ethi_popup_sort_ascending), 2), 1605 E_POPUP_ITEM ( 1606 N_("Sort _Descending"), 1607 G_CALLBACK (ethi_popup_sort_descending), 2), 1608 E_POPUP_ITEM ( 1609 N_("_Unsort"), G_CALLBACK (ethi_popup_unsort), 0), 1610 E_POPUP_SEPARATOR, 1611 E_POPUP_ITEM ( 1612 N_("Group By This _Field"), 1613 G_CALLBACK (ethi_popup_group_field), 16), 1614 E_POPUP_ITEM ( 1615 N_("Group By _Box"), 1616 G_CALLBACK (ethi_popup_group_box), 128), 1617 E_POPUP_SEPARATOR, 1618 E_POPUP_ITEM ( 1619 N_("Remove This _Column"), 1620 G_CALLBACK (ethi_popup_remove_column), 8), 1621 E_POPUP_ITEM ( 1622 N_("Add a C_olumn..."), 1623 G_CALLBACK (ethi_popup_field_chooser), 0), 1624 E_POPUP_SEPARATOR, 1625 E_POPUP_ITEM ( 1626 N_("A_lignment"), 1627 G_CALLBACK (ethi_popup_alignment), 128), 1628 E_POPUP_ITEM ( 1629 N_("B_est Fit"), 1630 G_CALLBACK (ethi_popup_best_fit), 2), 1631 E_POPUP_ITEM ( 1632 N_("Format Column_s..."), 1633 G_CALLBACK (ethi_popup_format_columns), 128), 1634 E_POPUP_SEPARATOR, 1635 E_POPUP_ITEM ( 1636 N_("Custo_mize Current View..."), 1637 G_CALLBACK (ethi_popup_customize_view), 4), 1638 E_POPUP_TERMINATOR 1639 }; 1640 1641 static void 1642 sort_by_id (GtkWidget *menu_item, 1643 ETableHeaderItem *ethi) 1644 { 1645 ETableCol *ecol; 1646 gboolean clearfirst; 1647 gint col; 1648 1649 col = GPOINTER_TO_INT (g_object_get_data ( 1650 G_OBJECT (menu_item), "col-number")); 1651 ecol = e_table_header_get_column (ethi->full_header, col); 1652 clearfirst = e_table_sort_info_sorting_get_count (ethi->sort_info) > 1; 1653 1654 if (!clearfirst && ecol && 1655 e_table_sort_info_sorting_get_count (ethi->sort_info) == 1) { 1656 ETableSortColumn column; 1657 1658 column = e_table_sort_info_sorting_get_nth (ethi->sort_info, 0); 1659 clearfirst = ecol->sortable && ecol->col_idx != column.column; 1660 } 1661 1662 if (clearfirst) 1663 e_table_sort_info_sorting_truncate (ethi->sort_info, 0); 1664 1665 ethi_change_sort_state (ethi, ecol); 1666 } 1667 1668 static void 1669 popup_custom (GtkWidget *menu_item, 1670 EthiHeaderInfo *info) 1671 { 1672 ethi_popup_customize_view (menu_item, info); 1673 } 1674 1675 static void 1676 ethi_header_context_menu (ETableHeaderItem *ethi, 1677 GdkEventButton *event) 1678 { 1679 EthiHeaderInfo *info = g_new (EthiHeaderInfo, 1); 1680 GtkMenu *popup; 1681 gint ncol, sort_count, sort_col; 1682 GtkWidget *menu_item, *sub_menu; 1683 ETableSortColumn column; 1684 gboolean ascending = TRUE; 1685 d (g_print ("ethi_header_context_menu: \n")); 1686 1687 info->ethi = ethi; 1688 info->col = ethi_find_col_by_x (ethi, event->x); 1689 1690 popup = e_popup_menu_create_with_domain ( 1691 ethi_context_menu, 1692 1 + 1693 ((ethi->table || ethi->tree) ? 0 : 4) + 1694 ((e_table_header_count (ethi->eth) > 1) ? 0 : 8), 1695 ((e_table_sort_info_get_can_group (ethi->sort_info)) ? 0 : 16) + 1696 128, info, GETTEXT_PACKAGE); 1697 1698 menu_item = gtk_menu_item_new_with_mnemonic (_("_Sort By")); 1699 gtk_widget_show (menu_item); 1700 sub_menu = gtk_menu_new (); 1701 gtk_widget_show (sub_menu); 1702 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), sub_menu); 1703 gtk_menu_shell_prepend (GTK_MENU_SHELL (popup), menu_item); 1704 1705 sort_count = e_table_sort_info_sorting_get_count (ethi->sort_info); 1706 1707 if (sort_count > 1 || sort_count < 1) 1708 sort_col = -1; /* Custom sorting */ 1709 else { 1710 column = e_table_sort_info_sorting_get_nth (ethi->sort_info, 0); 1711 sort_col = column.column; 1712 ascending = column.ascending; 1713 } 1714 1715 /* Custom */ 1716 menu_item = gtk_check_menu_item_new_with_mnemonic (_("_Custom")); 1717 gtk_widget_show (menu_item); 1718 gtk_menu_shell_prepend (GTK_MENU_SHELL (sub_menu), menu_item); 1719 if (sort_col == -1) 1720 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), TRUE); 1721 gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (menu_item), TRUE); 1722 g_signal_connect ( 1723 menu_item, "activate", 1724 G_CALLBACK (popup_custom), info); 1725 1726 /* Show a seperator */ 1727 menu_item = gtk_separator_menu_item_new (); 1728 gtk_widget_show (menu_item); 1729 gtk_menu_shell_prepend (GTK_MENU_SHELL (sub_menu), menu_item); 1730 /* Headers */ 1731 for (ncol = 0; ncol < ethi->full_header->col_count; ncol++) 1732 { 1733 gchar *text = NULL; 1734 1735 if (!ethi->full_header->columns[ncol]->sortable || 1736 ethi->full_header->columns[ncol]->disabled) 1737 continue; 1738 1739 if (ncol == sort_col) { 1740 text = g_strdup_printf ( 1741 "%s (%s)", 1742 ethi->full_header->columns[ncol]->text, 1743 ascending ? _("Ascending"):_("Descending")); 1744 menu_item = gtk_check_menu_item_new_with_label (text); 1745 g_free (text); 1746 } else 1747 menu_item = gtk_check_menu_item_new_with_label ( 1748 ethi->full_header->columns[ncol]->text); 1749 1750 gtk_widget_show (menu_item); 1751 gtk_menu_shell_prepend (GTK_MENU_SHELL (sub_menu), menu_item); 1752 1753 if (ncol == sort_col) 1754 gtk_check_menu_item_set_active ( 1755 GTK_CHECK_MENU_ITEM (menu_item), TRUE); 1756 gtk_check_menu_item_set_draw_as_radio ( 1757 GTK_CHECK_MENU_ITEM (menu_item), TRUE); 1758 g_object_set_data ( 1759 G_OBJECT (menu_item), "col-number", 1760 GINT_TO_POINTER (ncol)); 1761 g_signal_connect ( 1762 menu_item, "activate", 1763 G_CALLBACK (sort_by_id), ethi); 1764 } 1765 1766 g_object_ref_sink (popup); 1767 g_signal_connect ( 1768 popup, "selection-done", 1769 G_CALLBACK (free_popup_info), info); 1770 1771 gtk_menu_popup ( 1772 GTK_MENU (popup), 1773 NULL, NULL, NULL, NULL, 1774 event->button, event->time); 1775 } 1776 1777 static void 1778 ethi_button_pressed (ETableHeaderItem *ethi, 1779 GdkEventButton *event) 1780 { 1781 g_signal_emit (ethi, ethi_signals[BUTTON_PRESSED], 0, event); 1782 } 1783 1784 void 1785 ethi_change_sort_state (ETableHeaderItem *ethi, 1786 ETableCol *col) 1787 { 1788 gint model_col = -1; 1789 gint length; 1790 gint i; 1791 gboolean found = FALSE; 1792 1793 if (col == NULL) 1794 return; 1795 1796 if (col->sortable) 1797 model_col = col->col_idx; 1798 1799 length = e_table_sort_info_grouping_get_count (ethi->sort_info); 1800 for (i = 0; i < length; i++) { 1801 ETableSortColumn column; 1802 1803 column = e_table_sort_info_grouping_get_nth ( 1804 ethi->sort_info, i); 1805 1806 if (model_col == column.column || model_col == -1) { 1807 gint ascending = column.ascending; 1808 ascending = !ascending; 1809 column.ascending = ascending; 1810 e_table_sort_info_grouping_set_nth (ethi->sort_info, i, column); 1811 found = TRUE; 1812 if (model_col != -1) 1813 break; 1814 } 1815 } 1816 1817 if (!found) { 1818 length = e_table_sort_info_sorting_get_count (ethi->sort_info); 1819 for (i = 0; i < length; i++) { 1820 ETableSortColumn column; 1821 1822 column = e_table_sort_info_sorting_get_nth ( 1823 ethi->sort_info, i); 1824 1825 if (model_col == column.column || model_col == -1) { 1826 gint ascending = column.ascending; 1827 1828 if (ascending == 0 && model_col != -1) { 1829 /* 1830 * This means the user has clicked twice 1831 * already, lets kill sorting of this column now. 1832 */ 1833 gint j; 1834 1835 for (j = i + 1; j < length; j++) 1836 e_table_sort_info_sorting_set_nth ( 1837 ethi->sort_info, j - 1, 1838 e_table_sort_info_sorting_get_nth ( 1839 ethi->sort_info, j)); 1840 1841 e_table_sort_info_sorting_truncate ( 1842 ethi->sort_info, length - 1); 1843 length--; 1844 i--; 1845 } else { 1846 ascending = !ascending; 1847 column.ascending = ascending; 1848 e_table_sort_info_sorting_set_nth ( 1849 ethi->sort_info, i, column); 1850 } 1851 found = TRUE; 1852 if (model_col != -1) 1853 break; 1854 } 1855 } 1856 } 1857 1858 if (!found && model_col != -1) { 1859 ETableSortColumn column; 1860 column.column = model_col; 1861 column.ascending = 1; 1862 e_table_sort_info_sorting_truncate (ethi->sort_info, 0); 1863 e_table_sort_info_sorting_set_nth (ethi->sort_info, 0, column); 1864 } 1865 } 1866 1867 /* 1868 * Handles the events on the ETableHeaderItem, particularly it handles resizing 1869 */ 1870 static gint 1871 ethi_event (GnomeCanvasItem *item, 1872 GdkEvent *e) 1873 { 1874 ETableHeaderItem *ethi = E_TABLE_HEADER_ITEM (item); 1875 GnomeCanvas *canvas = item->canvas; 1876 GdkWindow *window; 1877 const gboolean resizing = ETHI_RESIZING (ethi); 1878 gint x, y, start, col; 1879 gint was_maybe_drag = 0; 1880 1881 switch (e->type) { 1882 case GDK_ENTER_NOTIFY: 1883 convert (canvas, e->crossing.x, e->crossing.y, &x, &y); 1884 set_cursor (ethi, x); 1885 break; 1886 1887 case GDK_LEAVE_NOTIFY: 1888 window = gtk_widget_get_window (GTK_WIDGET (canvas)); 1889 gdk_window_set_cursor (window, NULL); 1890 break; 1891 1892 case GDK_MOTION_NOTIFY: 1893 1894 convert (canvas, e->motion.x, e->motion.y, &x, &y); 1895 if (resizing) { 1896 gint new_width; 1897 1898 if (ethi->resize_guide == NULL) { 1899 /* Quick hack until I actually bind the views */ 1900 ethi->resize_guide = GINT_TO_POINTER (1); 1901 1902 gnome_canvas_item_grab ( 1903 item, 1904 GDK_POINTER_MOTION_MASK | 1905 GDK_BUTTON_RELEASE_MASK, 1906 ethi->resize_cursor, 1907 e->button.time); 1908 } 1909 1910 new_width = x - ethi->resize_start_pos; 1911 1912 e_table_header_set_size (ethi->eth, ethi->resize_col, new_width); 1913 1914 gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ethi)); 1915 } else if (ethi_maybe_start_drag (ethi, &e->motion)) { 1916 ethi_start_drag (ethi, e); 1917 } else 1918 set_cursor (ethi, x); 1919 break; 1920 1921 case GDK_BUTTON_PRESS: 1922 if (e->button.button > 3) 1923 return FALSE; 1924 1925 convert (canvas, e->button.x, e->button.y, &x, &y); 1926 1927 if (is_pointer_on_division (ethi, x, &start, &col) && 1928 e->button.button == 1) { 1929 ETableCol *ecol; 1930 1931 /* 1932 * Record the important bits. 1933 * 1934 * By setting resize_pos to a non -1 value, 1935 * we know that we are being resized (used in the 1936 * other event handlers). 1937 */ 1938 ecol = e_table_header_get_column (ethi->eth, col); 1939 1940 if (!ecol->resizable) 1941 break; 1942 ethi->resize_col = col; 1943 ethi->resize_start_pos = start - ecol->width; 1944 ethi->resize_min_width = ecol->min_width; 1945 1946 if (ethi->table) 1947 e_table_freeze_state_change (ethi->table); 1948 else if (ethi->tree) 1949 e_tree_freeze_state_change (ethi->tree); 1950 } else { 1951 if (e->button.button == 1) { 1952 ethi->click_x = e->button.x; 1953 ethi->click_y = e->button.y; 1954 ethi->maybe_drag = TRUE; 1955 is_pointer_on_division (ethi, x, &start, &col); 1956 ethi->selected_col = col;
Assigned value is garbage or undefined
(emitted by clang-analyzer)

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

Assigned value is garbage or undefined
(emitted by clang-analyzer)

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

1957 if (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas))) 1958 e_canvas_item_grab_focus (item, TRUE); 1959 } else if (e->button.button == 3) { 1960 ethi_header_context_menu (ethi, &e->button); 1961 } else 1962 ethi_button_pressed (ethi, &e->button); 1963 } 1964 break; 1965 1966 case GDK_2BUTTON_PRESS: 1967 if (!resizing) 1968 break; 1969 1970 if (e->button.button != 1) 1971 break; 1972 else { 1973 gint width = 0; 1974 g_signal_emit_by_name ( 1975 ethi->eth, 1976 "request_width", 1977 (gint) ethi->resize_col, &width); 1978 /* Add 10 to stop it from "..."ing */ 1979 e_table_header_set_size (ethi->eth, ethi->resize_col, width + 10); 1980 1981 gnome_canvas_item_request_update (GNOME_CANVAS_ITEM (ethi)); 1982 ethi->maybe_drag = FALSE; 1983 } 1984 break; 1985 1986 case GDK_BUTTON_RELEASE: { 1987 gboolean needs_ungrab = FALSE; 1988 1989 was_maybe_drag = ethi->maybe_drag; 1990 1991 ethi->maybe_drag = FALSE; 1992 1993 if (ethi->resize_col != -1) { 1994 needs_ungrab = (ethi->resize_guide != NULL); 1995 ethi_end_resize (ethi); 1996 } else if (was_maybe_drag && ethi->sort_info) { 1997 ETableCol *ecol; 1998 1999 col = ethi_find_col_by_x (ethi, e->button.x); 2000 ecol = e_table_header_get_column (ethi->eth, col); 2001 ethi_change_sort_state (ethi, ecol); 2002 } 2003 2004 if (needs_ungrab) 2005 gnome_canvas_item_ungrab (item, e->button.time); 2006 2007 break; 2008 } 2009 case GDK_KEY_PRESS: 2010 if ((e->key.keyval == GDK_KEY_F10) && (e->key.state & GDK_SHIFT_MASK)) { 2011 EthiHeaderInfo *info = g_new (EthiHeaderInfo, 1); 2012 ETableCol *ecol; 2013 GtkMenu *popup; 2014 2015 info->ethi = ethi; 2016 info->col = ethi->selected_col; 2017 ecol = e_table_header_get_column (ethi->eth, info->col); 2018 2019 popup = e_popup_menu_create_with_domain ( 2020 ethi_context_menu, 2021 1 + 2022 (ecol->sortable ? 0 : 2) + 2023 ((ethi->table || ethi->tree) ? 0 : 4) + 2024 ((e_table_header_count (ethi->eth) > 1) ? 0 : 8), 2025 ((e_table_sort_info_get_can_group ( 2026 ethi->sort_info)) ? 0 : 16) + 2027 128, info, GETTEXT_PACKAGE); 2028 g_object_ref_sink (popup); 2029 g_signal_connect ( 2030 popup, "selection-done", 2031 G_CALLBACK (free_popup_info), info); 2032 gtk_menu_popup ( 2033 GTK_MENU (popup), 2034 NULL, NULL, NULL, NULL, 2035 0, GDK_CURRENT_TIME); 2036 } else if (e->key.keyval == GDK_KEY_space) { 2037 ETableCol *ecol; 2038 2039 ecol = e_table_header_get_column (ethi->eth, ethi->selected_col); 2040 ethi_change_sort_state (ethi, ecol); 2041 } else if ((e->key.keyval == GDK_KEY_Right) || 2042 (e->key.keyval == GDK_KEY_KP_Right)) { 2043 ETableCol *ecol; 2044 2045 if ((ethi->selected_col < 0) || 2046 (ethi->selected_col >= ethi->eth->col_count - 1)) 2047 ethi->selected_col = 0; 2048 else 2049 ethi->selected_col++; 2050 ecol = e_table_header_get_column (ethi->eth, ethi->selected_col); 2051 ethi_change_sort_state (ethi, ecol); 2052 } else if ((e->key.keyval == GDK_KEY_Left) || 2053 (e->key.keyval == GDK_KEY_KP_Left)) { 2054 ETableCol *ecol; 2055 2056 if ((ethi->selected_col <= 0) || 2057 (ethi->selected_col >= ethi->eth->col_count)) 2058 ethi->selected_col = ethi->eth->col_count - 1; 2059 else 2060 ethi->selected_col--; 2061 ecol = e_table_header_get_column (ethi->eth, ethi->selected_col); 2062 ethi_change_sort_state (ethi, ecol); 2063 } 2064 break; 2065 2066 default: 2067 return FALSE; 2068 } 2069 return TRUE; 2070 } 2071 2072 static void 2073 ethi_class_init (ETableHeaderItemClass *class) 2074 { 2075 GnomeCanvasItemClass *item_class = GNOME_CANVAS_ITEM_CLASS (class); 2076 GObjectClass *object_class = G_OBJECT_CLASS (class); 2077 2078 object_class->dispose = ethi_dispose; 2079 object_class->set_property = ethi_set_property; 2080 object_class->get_property = ethi_get_property; 2081 2082 item_class->update = ethi_update; 2083 item_class->realize = ethi_realize; 2084 item_class->unrealize = ethi_unrealize; 2085 item_class->draw = ethi_draw; 2086 item_class->point = ethi_point; 2087 item_class->event = ethi_event; 2088 2089 g_object_class_install_property ( 2090 object_class, 2091 PROP_DND_CODE, 2092 g_param_spec_string ( 2093 "dnd_code", 2094 "DnD code", 2095 NULL, 2096 NULL, 2097 G_PARAM_READWRITE)); 2098 2099 g_object_class_install_property ( 2100 object_class, 2101 PROP_TABLE_FONT_DESC, 2102 g_param_spec_boxed ( 2103 "font-desc", 2104 "Font Description", 2105 NULL, 2106 PANGO_TYPE_FONT_DESCRIPTION, 2107 G_PARAM_WRITABLE)); 2108 2109 g_object_class_install_property ( 2110 object_class, 2111 PROP_FULL_HEADER, 2112 g_param_spec_object ( 2113 "full_header", 2114 "Full Header", 2115 NULL, 2116 E_TYPE_TABLE_HEADER, 2117 G_PARAM_READWRITE)); 2118 2119 g_object_class_install_property ( 2120 object_class, 2121 PROP_TABLE_HEADER, 2122 g_param_spec_object ( 2123 "ETableHeader", 2124 "Header", 2125 NULL, 2126 E_TYPE_TABLE_HEADER, 2127 G_PARAM_WRITABLE)); 2128 2129 g_object_class_install_property ( 2130 object_class, 2131 PROP_SORT_INFO, 2132 g_param_spec_object ( 2133 "sort_info", 2134 "Sort Info", 2135 NULL, 2136 E_TYPE_TABLE_SORT_INFO, 2137 G_PARAM_WRITABLE)); 2138 2139 g_object_class_install_property ( 2140 object_class, 2141 PROP_TABLE, 2142 g_param_spec_object ( 2143 "table", 2144 "Table", 2145 NULL, 2146 E_TYPE_TABLE, 2147 G_PARAM_WRITABLE)); 2148 2149 g_object_class_install_property ( 2150 object_class, 2151 PROP_TREE, 2152 g_param_spec_object ( 2153 "tree", 2154 "Tree", 2155 NULL, 2156 E_TYPE_TREE, 2157 G_PARAM_WRITABLE)); 2158 2159 ethi_signals[BUTTON_PRESSED] = g_signal_new ( 2160 "button_pressed", 2161 G_OBJECT_CLASS_TYPE (object_class), 2162 G_SIGNAL_RUN_LAST, 2163 G_STRUCT_OFFSET (ETableHeaderItemClass, button_pressed), 2164 NULL, NULL, 2165 g_cclosure_marshal_VOID__BOXED, 2166 G_TYPE_NONE, 1, 2167 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); 2168 } 2169 2170 static void 2171 ethi_init (ETableHeaderItem *ethi) 2172 { 2173 GnomeCanvasItem *item = GNOME_CANVAS_ITEM (ethi); 2174 2175 ethi->resize_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW); 2176 2177 ethi->resize_col = -1; 2178 2179 item->x1 = 0; 2180 item->y1 = 0; 2181 item->x2 = 0; 2182 item->y2 = 0; 2183 2184 ethi->drag_col = -1; 2185 ethi->drag_mark = -1; 2186 2187 ethi->sort_info = NULL; 2188 2189 ethi->sort_info_changed_id = 0; 2190 ethi->group_info_changed_id = 0; 2191 2192 ethi->group_indent_width = 0; 2193 ethi->table = NULL; 2194 ethi->tree = NULL; 2195 2196 ethi->selected_col = 0; 2197 }