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), ði->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);
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
(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;
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
(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 }