Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
e-reflow.c:378:35 | clang-analyzer | Access to field 'data' results in a dereference of a null pointer (loaded from variable 'list') | ||
e-reflow.c:378:35 | clang-analyzer | Access to field 'data' results in a dereference of a null pointer (loaded from variable 'list') |
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with the program; if not, see <http://www.gnu.org/licenses/>
15 *
16 *
17 * Authors:
18 * Chris Lahey <clahey@ximian.com>
19 *
20 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <math.h>
28 #include <string.h>
29
30 #include <gdk/gdkkeysyms.h>
31 #include <gtk/gtk.h>
32
33 #include "text/e-text.h"
34 #include <glib/gi18n.h>
35 #include "e-util/e-util.h"
36 #include "e-util/e-unicode.h"
37
38 #include "misc/e-canvas.h"
39 #include "misc/e-canvas-utils.h"
40 #include "e-reflow.h"
41 #include "misc/e-selection-model-simple.h"
42
43 static gboolean e_reflow_event (GnomeCanvasItem *item, GdkEvent *event);
44 static void e_reflow_realize (GnomeCanvasItem *item);
45 static void e_reflow_unrealize (GnomeCanvasItem *item);
46 static void e_reflow_draw (GnomeCanvasItem *item, cairo_t *cr,
47 gint x, gint y, gint width, gint height);
48 static void e_reflow_update (GnomeCanvasItem *item, const cairo_matrix_t *i2c, gint flags);
49 static GnomeCanvasItem *e_reflow_point (GnomeCanvasItem *item, gdouble x, gdouble y, gint cx, gint cy);
50 static void e_reflow_reflow (GnomeCanvasItem *item, gint flags);
51 static void set_empty (EReflow *reflow);
52
53 static void e_reflow_resize_children (GnomeCanvasItem *item);
54
55 #define E_REFLOW_DIVIDER_WIDTH 2
56 #define E_REFLOW_BORDER_WIDTH 7
57 #define E_REFLOW_FULL_GUTTER (E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH * 2)
58
59 G_DEFINE_TYPE (EReflow, e_reflow, GNOME_TYPE_CANVAS_GROUP)
60
61 enum {
62 PROP_0,
63 PROP_MINIMUM_WIDTH,
64 PROP_WIDTH,
65 PROP_HEIGHT,
66 PROP_EMPTY_MESSAGE,
67 PROP_MODEL,
68 PROP_COLUMN_WIDTH
69 };
70
71 enum {
72 SELECTION_EVENT,
73 COLUMN_WIDTH_CHANGED,
74 LAST_SIGNAL
75 };
76
77 static guint signals[LAST_SIGNAL] = {0, };
78
79 static GHashTable *
80 er_create_cmp_cache (gpointer user_data)
81 {
82 EReflow *reflow = user_data;
83 return e_reflow_model_create_cmp_cache (reflow->model);
84 }
85
86 static gint
87 er_compare (gint i1,
88 gint i2,
89 GHashTable *cmp_cache,
90 gpointer user_data)
91 {
92 EReflow *reflow = user_data;
93 return e_reflow_model_compare (reflow->model, i1, i2, cmp_cache);
94 }
95
96 static gint
97 e_reflow_pick_line (EReflow *reflow,
98 gdouble x)
99 {
100 x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
101 x /= reflow->column_width + E_REFLOW_FULL_GUTTER;
102 return x;
103 }
104
105 static gint
106 er_find_item (EReflow *reflow,
107 GnomeCanvasItem *item)
108 {
109 gint i;
110 for (i = 0; i < reflow->count; i++) {
111 if (reflow->items[i] == item)
112 return i;
113 }
114 return -1;
115 }
116
117 static void
118 e_reflow_resize_children (GnomeCanvasItem *item)
119 {
120 EReflow *reflow;
121 gint i;
122 gint count;
123
124 reflow = E_REFLOW (item);
125
126 count = reflow->count;
127 for (i = 0; i < count; i++) {
128 if (reflow->items[i])
129 gnome_canvas_item_set (
130 reflow->items[i],
131 "width", (gdouble) reflow->column_width,
132 NULL);
133 }
134 }
135
136 static inline void
137 e_reflow_update_selection_row (EReflow *reflow,
138 gint row)
139 {
140 if (reflow->items[row]) {
141 g_object_set (
142 reflow->items[row],
143 "selected", e_selection_model_is_row_selected (E_SELECTION_MODEL (reflow->selection), row),
144 NULL);
145 } else if (e_selection_model_is_row_selected (E_SELECTION_MODEL (reflow->selection), row)) {
146 reflow->items[row] = e_reflow_model_incarnate (reflow->model, row, GNOME_CANVAS_GROUP (reflow));
147 g_object_set (
148 reflow->items[row],
149 "selected", e_selection_model_is_row_selected (E_SELECTION_MODEL (reflow->selection), row),
150 "width", (gdouble) reflow->column_width,
151 NULL);
152 }
153 }
154
155 static void
156 e_reflow_update_selection (EReflow *reflow)
157 {
158 gint i;
159 gint count;
160
161 count = reflow->count;
162 for (i = 0; i < count; i++) {
163 e_reflow_update_selection_row (reflow, i);
164 }
165 }
166
167 static void
168 selection_changed (ESelectionModel *selection,
169 EReflow *reflow)
170 {
171 e_reflow_update_selection (reflow);
172 }
173
174 static void
175 selection_row_changed (ESelectionModel *selection,
176 gint row,
177 EReflow *reflow)
178 {
179 e_reflow_update_selection_row (reflow, row);
180 }
181
182 static gboolean
183 do_adjustment (gpointer user_data)
184 {
185 gint row;
186 GtkLayout *layout;
187 GtkAdjustment *adjustment;
188 gdouble page_size;
189 gdouble value, min_value, max_value;
190 EReflow *reflow = user_data;
191
192 row = reflow->cursor_row;
193 if (row == -1)
194 return FALSE;
195
196 layout = GTK_LAYOUT (GNOME_CANVAS_ITEM (reflow)->canvas);
197 adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (layout));
198
199 value = gtk_adjustment_get_value (adjustment);
200 page_size = gtk_adjustment_get_page_size (adjustment);
201
202 if ((!reflow->items) || (!reflow->items[row]))
203 return TRUE;
204 min_value = reflow->items[row]->x2 - page_size;
205 max_value = reflow->items[row]->x1;
206
207 if (value < min_value)
208 value = min_value;
209
210 if (value > max_value)
211 value = max_value;
212
213 if (value != gtk_adjustment_get_value (adjustment))
214 gtk_adjustment_set_value (adjustment, value);
215
216 reflow->do_adjustment_idle_id = 0;
217
218 return FALSE;
219 }
220
221 static void
222 cursor_changed (ESelectionModel *selection,
223 gint row,
224 gint col,
225 EReflow *reflow)
226 {
227 gint count = reflow->count;
228 gint old_cursor = reflow->cursor_row;
229
230 if (old_cursor < count && old_cursor >= 0) {
231 if (reflow->items[old_cursor]) {
232 g_object_set (
233 reflow->items[old_cursor],
234 "has_cursor", FALSE,
235 NULL);
236 }
237 }
238
239 reflow->cursor_row = row;
240
241 if (row < count && row >= 0) {
242 if (reflow->items[row]) {
243 g_object_set (
244 reflow->items[row],
245 "has_cursor", TRUE,
246 NULL);
247 } else {
248 reflow->items[row] = e_reflow_model_incarnate (reflow->model, row, GNOME_CANVAS_GROUP (reflow));
249 g_object_set (
250 reflow->items[row],
251 "has_cursor", TRUE,
252 "width", (gdouble) reflow->column_width,
253 NULL);
254 }
255 }
256
257 if (reflow->do_adjustment_idle_id == 0)
258 reflow->do_adjustment_idle_id = g_idle_add (do_adjustment, reflow);
259
260 }
261
262 static void
263 incarnate (EReflow *reflow)
264 {
265 gint column_width;
266 gint first_column;
267 gint last_column;
268 gint first_cell;
269 gint last_cell;
270 gint i;
271 GtkLayout *layout;
272 GtkAdjustment *adjustment;
273 gdouble value;
274 gdouble page_size;
275
276 layout = GTK_LAYOUT (GNOME_CANVAS_ITEM (reflow)->canvas);
277 adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (layout));
278
279 value = gtk_adjustment_get_value (adjustment);
280 page_size = gtk_adjustment_get_page_size (adjustment);
281
282 column_width = reflow->column_width;
283
284 first_column = value - 1 + E_REFLOW_BORDER_WIDTH;
285 first_column /= column_width + E_REFLOW_FULL_GUTTER;
286
287 last_column = value + page_size + 1 - E_REFLOW_BORDER_WIDTH - E_REFLOW_DIVIDER_WIDTH;
288 last_column /= column_width + E_REFLOW_FULL_GUTTER;
289 last_column++;
290
291 if (first_column >= 0 && first_column < reflow->column_count)
292 first_cell = reflow->columns[first_column];
293 else
294 first_cell = 0;
295
296 if (last_column >= 0 && last_column < reflow->column_count)
297 last_cell = reflow->columns[last_column];
298 else
299 last_cell = reflow->count;
300
301 for (i = first_cell; i < last_cell; i++) {
302 gint unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
303 if (reflow->items[unsorted] == NULL) {
304 if (reflow->model) {
305 reflow->items[unsorted] = e_reflow_model_incarnate (reflow->model, unsorted, GNOME_CANVAS_GROUP (reflow));
306 g_object_set (
307 reflow->items[unsorted],
308 "selected", e_selection_model_is_row_selected (E_SELECTION_MODEL (reflow->selection), unsorted),
309 "width", (gdouble) reflow->column_width,
310 NULL);
311 }
312 }
313 }
314 reflow->incarnate_idle_id = 0;
315 }
316
317 static gboolean
318 invoke_incarnate (gpointer user_data)
319 {
320 EReflow *reflow = user_data;
321 incarnate (reflow);
322 return FALSE;
323 }
324
325 static void
326 queue_incarnate (EReflow *reflow)
327 {
328 if (reflow->incarnate_idle_id == 0)
329 reflow->incarnate_idle_id =
330 g_idle_add_full (25, invoke_incarnate, reflow, NULL);
331 }
332
333 static void
334 reflow_columns (EReflow *reflow)
335 {
336 GSList *list;
337 gint count;
338 gint start;
339 gint i;
340 gint column_count, column_start;
341 gdouble running_height;
342
343 if (reflow->reflow_from_column <= 1) {
344 start = 0;
345 column_count = 1;
346 column_start = 0;
347 }
348 else {
349 /* we start one column before the earliest new entry,
350 * so we can handle the case where the new entry is
351 * inserted at the start of the column */
352 column_start = reflow->reflow_from_column - 1;
353 start = reflow->columns[column_start];
354 column_count = column_start + 1;
355 }
356
357 list = NULL;
358
359 running_height = E_REFLOW_BORDER_WIDTH;
360
361 count = reflow->count - start;
362 for (i = start; i < count; i++) {
363 gint unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
364 if (i != 0 && running_height + reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH > reflow->height) {
365 list = g_slist_prepend (list, GINT_TO_POINTER (i));
366 column_count++;
367 running_height = E_REFLOW_BORDER_WIDTH * 2 + reflow->heights[unsorted];
368 } else
369 running_height += reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH;
370 }
371
372 reflow->column_count = column_count;
373 reflow->columns = g_renew (int, reflow->columns, column_count);
374 column_count--;
375
376 for (; column_count > column_start; column_count--) {
377 GSList *to_free;
378 reflow->columns[column_count] = GPOINTER_TO_INT (list->data);
(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)
379 to_free = list;
380 list = list->next;
381 g_slist_free_1 (to_free);
382 }
383 reflow->columns[column_start] = start;
384
385 queue_incarnate (reflow);
386
387 reflow->need_reflow_columns = FALSE;
388 reflow->reflow_from_column = -1;
389 }
390
391 static void
392 item_changed (EReflowModel *model,
393 gint i,
394 EReflow *reflow)
395 {
396 if (i < 0 || i >= reflow->count)
397 return;
398
399 reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow));
400 if (reflow->items[i] != NULL)
401 e_reflow_model_reincarnate (model, i, reflow->items[i]);
402 e_sorter_array_clean (reflow->sorter);
403 reflow->reflow_from_column = -1;
404 reflow->need_reflow_columns = TRUE;
405 e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (reflow));
406 }
407
408 static void
409 item_removed (EReflowModel *model,
410 gint i,
411 EReflow *reflow)
412 {
413 gint c;
414 gint sorted;
415
416 if (i < 0 || i >= reflow->count)
417 return;
418
419 sorted = e_sorter_model_to_sorted (E_SORTER (reflow->sorter), i);
420 for (c = reflow->column_count - 1; c >= 0; c--) {
421 gint start_of_column = reflow->columns[c];
422
423 if (start_of_column <= sorted) {
424 if (reflow->reflow_from_column == -1
425 || reflow->reflow_from_column > c) {
426 reflow->reflow_from_column = c;
427 }
428 break;
429 }
430 }
431
432 if (reflow->items[i])
433 g_object_run_dispose (G_OBJECT (reflow->items[i]));
434
435 memmove (reflow->heights + i, reflow->heights + i + 1, (reflow->count - i - 1) * sizeof (gint));
436 memmove (reflow->items + i, reflow->items + i + 1, (reflow->count - i - 1) * sizeof (GnomeCanvasItem *));
437
438 reflow->count--;
439
440 reflow->heights[reflow->count] = 0;
441 reflow->items[reflow->count] = NULL;
442
443 reflow->need_reflow_columns = TRUE;
444 set_empty (reflow);
445 e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (reflow));
446
447 e_sorter_array_set_count (reflow->sorter, reflow->count);
448
449 e_selection_model_simple_delete_rows (E_SELECTION_MODEL_SIMPLE (reflow->selection), i, 1);
450 }
451
452 static void
453 items_inserted (EReflowModel *model,
454 gint position,
455 gint count,
456 EReflow *reflow)
457 {
458 gint i, oldcount;
459
460 if (position < 0 || position > reflow->count)
461 return;
462
463 oldcount = reflow->count;
464
465 reflow->count += count;
466
467 if (reflow->count > reflow->allocated_count) {
468 while (reflow->count > reflow->allocated_count)
469 reflow->allocated_count += 256;
470 reflow->heights = g_renew (int, reflow->heights, reflow->allocated_count);
471 reflow->items = g_renew (GnomeCanvasItem *, reflow->items, reflow->allocated_count);
472 }
473 memmove (reflow->heights + position + count, reflow->heights + position, (reflow->count - position - count) * sizeof (gint));
474 memmove (reflow->items + position + count, reflow->items + position, (reflow->count - position - count) * sizeof (GnomeCanvasItem *));
475 for (i = position; i < position + count; i++) {
476 reflow->items[i] = NULL;
477 reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow));
478 }
479
480 e_selection_model_simple_set_row_count (E_SELECTION_MODEL_SIMPLE (reflow->selection), reflow->count);
481 if (position == oldcount)
482 e_sorter_array_append (reflow->sorter, count);
483 else
484 e_sorter_array_set_count (reflow->sorter, reflow->count);
485
486 for (i = position; i < position + count; i++) {
487 gint sorted = e_sorter_model_to_sorted (E_SORTER (reflow->sorter), i);
488 gint c;
489
490 for (c = reflow->column_count - 1; c >= 0; c--) {
491 gint start_of_column = reflow->columns[c];
492
493 if (start_of_column <= sorted) {
494 if (reflow->reflow_from_column == -1
495 || reflow->reflow_from_column > c) {
496 reflow->reflow_from_column = c;
497 }
498 break;
499 }
500 }
501 }
502
503 reflow->need_reflow_columns = TRUE;
504 set_empty (reflow);
505 e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (reflow));
506 }
507
508 static void
509 model_changed (EReflowModel *model,
510 EReflow *reflow)
511 {
512 gint i;
513 gint count;
514 gint oldcount;
515
516 count = reflow->count;
517 oldcount = count;
518
519 for (i = 0; i < count; i++) {
520 if (reflow->items[i])
521 g_object_run_dispose (G_OBJECT (reflow->items[i]));
522 }
523 g_free (reflow->items);
524 g_free (reflow->heights);
525 reflow->count = e_reflow_model_count (model);
526 reflow->allocated_count = reflow->count;
527 reflow->items = g_new (GnomeCanvasItem *, reflow->count);
528 reflow->heights = g_new (int, reflow->count);
529
530 count = reflow->count;
531 for (i = 0; i < count; i++) {
532 reflow->items[i] = NULL;
533 reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow));
534 }
535
536 e_selection_model_simple_set_row_count (E_SELECTION_MODEL_SIMPLE (reflow->selection), count);
537 e_sorter_array_set_count (reflow->sorter, reflow->count);
538
539 reflow->need_reflow_columns = TRUE;
540 if (oldcount > reflow->count)
541 reflow_columns (reflow);
542 set_empty (reflow);
543 e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (reflow));
544 }
545
546 static void
547 comparison_changed (EReflowModel *model,
548 EReflow *reflow)
549 {
550 e_sorter_array_clean (reflow->sorter);
551 reflow->reflow_from_column = -1;
552 reflow->need_reflow_columns = TRUE;
553 e_canvas_item_request_reflow (GNOME_CANVAS_ITEM (reflow));
554 }
555
556 static void
557 set_empty (EReflow *reflow)
558 {
559 if (reflow->count == 0) {
560 if (reflow->empty_text) {
561 if (reflow->empty_message) {
562 gnome_canvas_item_set (
563 reflow->empty_text,
564 "width", reflow->minimum_width,
565 "text", reflow->empty_message,
566 NULL);
567 e_canvas_item_move_absolute (
568 reflow->empty_text,
569 reflow->minimum_width / 2,
570 0);
571 } else {
572 g_object_run_dispose (G_OBJECT (reflow->empty_text));
573 reflow->empty_text = NULL;
574 }
575 } else {
576 if (reflow->empty_message) {
577 reflow->empty_text = gnome_canvas_item_new (
578 GNOME_CANVAS_GROUP (reflow),
579 e_text_get_type (),
580 "width", reflow->minimum_width,
581 "clip", TRUE,
582 "use_ellipsis", TRUE,
583 "justification", GTK_JUSTIFY_CENTER,
584 "text", reflow->empty_message,
585 NULL);
586 e_canvas_item_move_absolute (
587 reflow->empty_text,
588 reflow->minimum_width / 2,
589 0);
590 }
591 }
592 } else {
593 if (reflow->empty_text) {
594 g_object_run_dispose (G_OBJECT (reflow->empty_text));
595 reflow->empty_text = NULL;
596 }
597 }
598 }
599
600 static void
601 disconnect_model (EReflow *reflow)
602 {
603 if (reflow->model == NULL)
604 return;
605
606 g_signal_handler_disconnect (
607 reflow->model,
608 reflow->model_changed_id);
609 g_signal_handler_disconnect (
610 reflow->model,
611 reflow->comparison_changed_id);
612 g_signal_handler_disconnect (
613 reflow->model,
614 reflow->model_items_inserted_id);
615 g_signal_handler_disconnect (
616 reflow->model,
617 reflow->model_item_removed_id);
618 g_signal_handler_disconnect (
619 reflow->model,
620 reflow->model_item_changed_id);
621 g_object_unref (reflow->model);
622
623 reflow->model_changed_id = 0;
624 reflow->comparison_changed_id = 0;
625 reflow->model_items_inserted_id = 0;
626 reflow->model_item_removed_id = 0;
627 reflow->model_item_changed_id = 0;
628 reflow->model = NULL;
629 }
630
631 static void
632 disconnect_selection (EReflow *reflow)
633 {
634 if (reflow->selection == NULL)
635 return;
636
637 g_signal_handler_disconnect (
638 reflow->selection,
639 reflow->selection_changed_id);
640 g_signal_handler_disconnect (
641 reflow->selection,
642 reflow->selection_row_changed_id);
643 g_signal_handler_disconnect (
644 reflow->selection,
645 reflow->cursor_changed_id);
646 g_object_unref (reflow->selection);
647
648 reflow->selection_changed_id = 0;
649 reflow->selection_row_changed_id = 0;
650 reflow->cursor_changed_id = 0;
651 reflow->selection = NULL;
652 }
653
654 static void
655 connect_model (EReflow *reflow,
656 EReflowModel *model)
657 {
658 if (reflow->model != NULL)
659 disconnect_model (reflow);
660
661 if (model == NULL)
662 return;
663
664 reflow->model = g_object_ref (model);
665
666 reflow->model_changed_id = g_signal_connect (
667 reflow->model, "model_changed",
668 G_CALLBACK (model_changed), reflow);
669
670 reflow->comparison_changed_id = g_signal_connect (
671 reflow->model, "comparison_changed",
672 G_CALLBACK (comparison_changed), reflow);
673
674 reflow->model_items_inserted_id = g_signal_connect (
675 reflow->model, "model_items_inserted",
676 G_CALLBACK (items_inserted), reflow);
677
678 reflow->model_item_removed_id = g_signal_connect (
679 reflow->model, "model_item_removed",
680 G_CALLBACK (item_removed), reflow);
681
682 reflow->model_item_changed_id = g_signal_connect (
683 reflow->model, "model_item_changed",
684 G_CALLBACK (item_changed), reflow);
685
686 model_changed (model, reflow);
687 }
688
689 static void
690 adjustment_changed (GtkAdjustment *adjustment,
691 EReflow *reflow)
692 {
693 queue_incarnate (reflow);
694 }
695
696 static void
697 disconnect_adjustment (EReflow *reflow)
698 {
699 if (reflow->adjustment == NULL)
700 return;
701
702 g_signal_handler_disconnect (
703 reflow->adjustment,
704 reflow->adjustment_changed_id);
705 g_signal_handler_disconnect (
706 reflow->adjustment,
707 reflow->adjustment_value_changed_id);
708
709 g_object_unref (reflow->adjustment);
710
711 reflow->adjustment_changed_id = 0;
712 reflow->adjustment_value_changed_id = 0;
713 reflow->adjustment = NULL;
714 }
715
716 static void
717 connect_adjustment (EReflow *reflow,
718 GtkAdjustment *adjustment)
719 {
720 if (reflow->adjustment != NULL)
721 disconnect_adjustment (reflow);
722
723 if (adjustment == NULL)
724 return;
725
726 reflow->adjustment = g_object_ref (adjustment);
727
728 reflow->adjustment_changed_id = g_signal_connect (
729 adjustment, "changed",
730 G_CALLBACK (adjustment_changed), reflow);
731
732 reflow->adjustment_value_changed_id = g_signal_connect (
733 adjustment, "value_changed",
734 G_CALLBACK (adjustment_changed), reflow);
735 }
736
737 #if 0
738 static void
739 set_scroll_adjustments (GtkLayout *layout,
740 GtkAdjustment *hadj,
741 GtkAdjustment *vadj,
742 EReflow *reflow)
743 {
744 connect_adjustment (reflow, hadj);
745 }
746
747 static void
748 connect_set_adjustment (EReflow *reflow)
749 {
750 reflow->set_scroll_adjustments_id = g_signal_connect (
751 GNOME_CANVAS_ITEM (reflow)->canvas, "set_scroll_adjustments",
752 G_CALLBACK (set_scroll_adjustments), reflow);
753 }
754 #endif
755
756 static void
757 disconnect_set_adjustment (EReflow *reflow)
758 {
759 if (reflow->set_scroll_adjustments_id != 0) {
760 g_signal_handler_disconnect (
761 GNOME_CANVAS_ITEM (reflow)->canvas,
762 reflow->set_scroll_adjustments_id);
763 reflow->set_scroll_adjustments_id = 0;
764 }
765 }
766
767 static void
768 column_width_changed (EReflow *reflow)
769 {
770 g_signal_emit (reflow, signals[COLUMN_WIDTH_CHANGED], 0, reflow->column_width);
771 }
772
773 /* Virtual functions */
774 static void
775 e_reflow_set_property (GObject *object,
776 guint property_id,
777 const GValue *value,
778 GParamSpec *pspec)
779 {
780 GnomeCanvasItem *item;
781 EReflow *reflow;
782
783 item = GNOME_CANVAS_ITEM (object);
784 reflow = E_REFLOW (object);
785
786 switch (property_id) {
787 case PROP_HEIGHT:
788 reflow->height = g_value_get_double (value);
789 reflow->need_reflow_columns = TRUE;
790 e_canvas_item_request_reflow (item);
791 break;
792 case PROP_MINIMUM_WIDTH:
793 reflow->minimum_width = g_value_get_double (value);
794 if (item->flags & GNOME_CANVAS_ITEM_REALIZED)
795 set_empty (reflow);
796 e_canvas_item_request_reflow (item);
797 break;
798 case PROP_EMPTY_MESSAGE:
799 g_free (reflow->empty_message);
800 reflow->empty_message = g_strdup (g_value_get_string (value));
801 if (item->flags & GNOME_CANVAS_ITEM_REALIZED)
802 set_empty (reflow);
803 break;
804 case PROP_MODEL:
805 connect_model (reflow, (EReflowModel *) g_value_get_object (value));
806 break;
807 case PROP_COLUMN_WIDTH:
808 if (reflow->column_width != g_value_get_double (value)) {
809 GtkLayout *layout;
810 GtkAdjustment *adjustment;
811 gdouble old_width = reflow->column_width;
812 gdouble step_increment;
813 gdouble page_size;
814
815 layout = GTK_LAYOUT (item->canvas);
816 adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (layout));
817 page_size = gtk_adjustment_get_page_size (adjustment);
818
819 reflow->column_width = g_value_get_double (value);
820 step_increment = (reflow->column_width +
821 E_REFLOW_FULL_GUTTER) / 2;
822 gtk_adjustment_set_step_increment (
823 adjustment, step_increment);
824 gtk_adjustment_set_page_increment (
825 adjustment, page_size - step_increment);
826 e_reflow_resize_children (item);
827 e_canvas_item_request_reflow (item);
828
829 reflow->need_column_resize = TRUE;
830 gnome_canvas_item_request_update (item);
831
832 if (old_width != reflow->column_width)
833 column_width_changed (reflow);
834 }
835 break;
836 }
837 }
838
839 static void
840 e_reflow_get_property (GObject *object,
841 guint property_id,
842 GValue *value,
843 GParamSpec *pspec)
844 {
845 EReflow *reflow;
846
847 reflow = E_REFLOW (object);
848
849 switch (property_id) {
850 case PROP_MINIMUM_WIDTH:
851 g_value_set_double (value, reflow->minimum_width);
852 break;
853 case PROP_WIDTH:
854 g_value_set_double (value, reflow->width);
855 break;
856 case PROP_HEIGHT:
857 g_value_set_double (value, reflow->height);
858 break;
859 case PROP_EMPTY_MESSAGE:
860 g_value_set_string (value, reflow->empty_message);
861 break;
862 case PROP_MODEL:
863 g_value_set_object (value, reflow->model);
864 break;
865 case PROP_COLUMN_WIDTH:
866 g_value_set_double (value, reflow->column_width);
867 break;
868 default:
869 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
870 break;
871 }
872 }
873
874 static void
875 e_reflow_dispose (GObject *object)
876 {
877 EReflow *reflow = E_REFLOW (object);
878
879 g_free (reflow->items);
880 g_free (reflow->heights);
881 g_free (reflow->columns);
882
883 reflow->items = NULL;
884 reflow->heights = NULL;
885 reflow->columns = NULL;
886 reflow->count = 0;
887 reflow->allocated_count = 0;
888
889 if (reflow->incarnate_idle_id)
890 g_source_remove (reflow->incarnate_idle_id);
891 reflow->incarnate_idle_id = 0;
892
893 if (reflow->do_adjustment_idle_id)
894 g_source_remove (reflow->do_adjustment_idle_id);
895 reflow->do_adjustment_idle_id = 0;
896
897 disconnect_model (reflow);
898 disconnect_selection (reflow);
899
900 g_free (reflow->empty_message);
901 reflow->empty_message = NULL;
902
903 if (reflow->sorter) {
904 g_object_unref (reflow->sorter);
905 reflow->sorter = NULL;
906 }
907
908 G_OBJECT_CLASS (e_reflow_parent_class)->dispose (object);
909 }
910
911 static void
912 e_reflow_realize (GnomeCanvasItem *item)
913 {
914 EReflow *reflow;
915 GtkAdjustment *adjustment;
916 gdouble page_increment;
917 gdouble step_increment;
918 gdouble page_size;
919 gint count;
920 gint i;
921
922 reflow = E_REFLOW (item);
923
924 if (GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->realize)
925 (* GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->realize) (item);
926
927 reflow->arrow_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
928 reflow->default_cursor = gdk_cursor_new (GDK_LEFT_PTR);
929
930 count = reflow->count;
931 for (i = 0; i < count; i++) {
932 if (reflow->items[i])
933 gnome_canvas_item_set (
934 reflow->items[i],
935 "width", reflow->column_width,
936 NULL);
937 }
938
939 set_empty (reflow);
940
941 reflow->need_reflow_columns = TRUE;
942 e_canvas_item_request_reflow (item);
943
944 adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (item->canvas));
945
946 #if 0
947 connect_set_adjustment (reflow);
948 #endif
949 connect_adjustment (reflow, adjustment);
950
951 page_size = gtk_adjustment_get_page_size (adjustment);
952 step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2;
953 page_increment = page_size - step_increment;
954 gtk_adjustment_set_step_increment (adjustment, step_increment);
955 gtk_adjustment_set_page_increment (adjustment, page_increment);
956 }
957
958 static void
959 e_reflow_unrealize (GnomeCanvasItem *item)
960 {
961 EReflow *reflow;
962
963 reflow = E_REFLOW (item);
964
965 g_object_unref (reflow->arrow_cursor);
966 g_object_unref (reflow->default_cursor);
967 reflow->arrow_cursor = NULL;
968 reflow->default_cursor = NULL;
969
970 g_free (reflow->columns);
971 reflow->columns = NULL;
972
973 disconnect_set_adjustment (reflow);
974 disconnect_adjustment (reflow);
975
976 if (GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->unrealize)
977 (* GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->unrealize) (item);
978 }
979
980 static gboolean
981 e_reflow_event (GnomeCanvasItem *item,
982 GdkEvent *event)
983 {
984 EReflow *reflow;
985 gint return_val = FALSE;
986
987 reflow = E_REFLOW (item);
988
989 switch (event->type)
990 {
991 case GDK_KEY_PRESS:
992 return_val = e_selection_model_key_press (reflow->selection, (GdkEventKey *) event);
993 break;
994 #if 0
995 if (event->key.keyval == GDK_Tab ||
996 event->key.keyval == GDK_KEY_KP_Tab ||
997 event->key.keyval == GDK_ISO_Left_Tab) {
998 gint i;
999 gint count;
1000 count = reflow->count;
1001 for (i = 0; i < count; i++) {
1002 gint unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
1003 GnomeCanvasItem *item = reflow->items[unsorted];
1004 EFocus has_focus;
1005 if (item) {
1006 g_object_get (
1007 item,
1008 "has_focus", &has_focus,
1009 NULL);
1010 if (has_focus) {
1011 if (event->key.state & GDK_SHIFT_MASK) {
1012 if (i == 0)
1013 return FALSE;
1014 i--;
1015 } else {
1016 if (i == count - 1)
1017 return FALSE;
1018 i++;
1019 }
1020
1021 unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
1022 if (reflow->items[unsorted] == NULL) {
1023 reflow->items[unsorted] = e_reflow_model_incarnate (reflow->model, unsorted, GNOME_CANVAS_GROUP (reflow));
1024 }
1025
1026 item = reflow->items[unsorted];
1027 gnome_canvas_item_set (
1028 item,
1029 "has_focus", (event->key.state & GDK_SHIFT_MASK) ? E_FOCUS_END : E_FOCUS_START,
1030 NULL);
1031 return TRUE;
1032 }
1033 }
1034 }
1035 }
1036 #endif
1037 case GDK_BUTTON_PRESS:
1038 switch (event->button.button)
1039 {
1040 case 1:
1041 {
1042 GdkEventButton *button = (GdkEventButton *) event;
1043 gdouble n_x;
1044 n_x = button->x;
1045 n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
1046 n_x = fmod (n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
1047
1048 if (button->y >= E_REFLOW_BORDER_WIDTH && button->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER) {
1049 /* don't allow to drag the first line*/
1050 if (e_reflow_pick_line (reflow, button->x) == 0)
1051 return TRUE;
1052 reflow->which_column_dragged = e_reflow_pick_line (reflow, button->x);
1053 reflow->start_x = reflow->which_column_dragged * (reflow->column_width + E_REFLOW_FULL_GUTTER) - E_REFLOW_DIVIDER_WIDTH / 2;
1054 reflow->temp_column_width = reflow->column_width;
1055 reflow->column_drag = TRUE;
1056
1057 gnome_canvas_item_grab (
1058 item,
1059 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK,
1060 reflow->arrow_cursor,
1061 button->time);
1062
1063 reflow->previous_temp_column_width = -1;
1064 reflow->need_column_resize = TRUE;
1065 gnome_canvas_item_request_update (item);
1066 return TRUE;
1067 }
1068 }
1069 break;
1070 case 4:
1071 {
1072 GtkLayout *layout;
1073 GtkAdjustment *adjustment;
1074 gdouble new_value;
1075
1076 layout = GTK_LAYOUT (item->canvas);
1077 adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (layout));
1078 new_value = gtk_adjustment_get_value (adjustment);
1079 new_value -= gtk_adjustment_get_step_increment (adjustment);
1080 gtk_adjustment_set_value (adjustment, new_value);
1081 }
1082 break;
1083 case 5:
1084 {
1085 GtkLayout *layout;
1086 GtkAdjustment *adjustment;
1087 gdouble new_value;
1088 gdouble page_size;
1089 gdouble upper;
1090
1091 layout = GTK_LAYOUT (item->canvas);
1092 adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (layout));
1093 new_value = gtk_adjustment_get_value (adjustment);
1094 new_value += gtk_adjustment_get_step_increment (adjustment);
1095 upper = gtk_adjustment_get_upper (adjustment);
1096 page_size = gtk_adjustment_get_page_size (adjustment);
1097 if (new_value > upper - page_size)
1098 new_value = upper - page_size;
1099 gtk_adjustment_set_value (adjustment, new_value);
1100 }
1101 break;
1102 }
1103 break;
1104 case GDK_BUTTON_RELEASE:
1105 if (reflow->column_drag) {
1106 gdouble old_width = reflow->column_width;
1107 GdkEventButton *button = (GdkEventButton *) event;
1108 GtkAdjustment *adjustment;
1109 GtkLayout *layout;
1110 gdouble value;
1111
1112 layout = GTK_LAYOUT (item->canvas);
1113 adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (layout));
1114 value = gtk_adjustment_get_value (adjustment);
1115
1116 reflow->temp_column_width = reflow->column_width +
1117 (button->x - reflow->start_x) / (reflow->which_column_dragged - e_reflow_pick_line (reflow, value));
1118 if (reflow->temp_column_width < 50)
1119 reflow->temp_column_width = 50;
1120 reflow->column_drag = FALSE;
1121 if (old_width != reflow->temp_column_width) {
1122 gdouble page_increment;
1123 gdouble step_increment;
1124 gdouble page_size;
1125
1126 page_size = gtk_adjustment_get_page_size (adjustment);
1127 gtk_adjustment_set_value (adjustment, value + e_reflow_pick_line (reflow, value) * (reflow->temp_column_width - reflow->column_width));
1128 reflow->column_width = reflow->temp_column_width;
1129 step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2;
1130 page_increment = page_size - step_increment;
1131 gtk_adjustment_set_step_increment (adjustment, step_increment);
1132 gtk_adjustment_set_page_increment (adjustment, page_increment);
1133 e_reflow_resize_children (item);
1134 e_canvas_item_request_reflow (item);
1135 gnome_canvas_request_redraw (item->canvas, 0, 0, reflow->width, reflow->height);
1136 column_width_changed (reflow);
1137 }
1138 reflow->need_column_resize = TRUE;
1139 gnome_canvas_item_request_update (item);
1140 gnome_canvas_item_ungrab (item, button->time);
1141 return TRUE;
1142 }
1143 break;
1144 case GDK_MOTION_NOTIFY:
1145 if (reflow->column_drag) {
1146 gdouble old_width = reflow->temp_column_width;
1147 GdkEventMotion *motion = (GdkEventMotion *) event;
1148 GtkAdjustment *adjustment;
1149 GtkLayout *layout;
1150 gdouble value;
1151
1152 layout = GTK_LAYOUT (item->canvas);
1153 adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (layout));
1154 value = gtk_adjustment_get_value (adjustment);
1155
1156 reflow->temp_column_width = reflow->column_width +
1157 (motion->x - reflow->start_x) / (reflow->which_column_dragged - e_reflow_pick_line (reflow, value));
1158 if (reflow->temp_column_width < 50)
1159 reflow->temp_column_width = 50;
1160 if (old_width != reflow->temp_column_width) {
1161 reflow->need_column_resize = TRUE;
1162 gnome_canvas_item_request_update (item);
1163 }
1164 return TRUE;
1165 } else {
1166 GdkEventMotion *motion = (GdkEventMotion *) event;
1167 GdkWindow *window;
1168 gdouble n_x;
1169
1170 n_x = motion->x;
1171 n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
1172 n_x = fmod (n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
1173
1174 window = gtk_widget_get_window (GTK_WIDGET (item->canvas));
1175
1176 if (motion->y >= E_REFLOW_BORDER_WIDTH && motion->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER) {
1177 if (reflow->default_cursor_shown) {
1178 gdk_window_set_cursor (window, reflow->arrow_cursor);
1179 reflow->default_cursor_shown = FALSE;
1180 }
1181 } else
1182 if (!reflow->default_cursor_shown) {
1183 gdk_window_set_cursor (window, reflow->default_cursor);
1184 reflow->default_cursor_shown = TRUE;
1185 }
1186
1187 }
1188 break;
1189 case GDK_ENTER_NOTIFY:
1190 if (!reflow->column_drag) {
1191 GdkEventCrossing *crossing = (GdkEventCrossing *) event;
1192 GdkWindow *window;
1193 gdouble n_x;
1194
1195 n_x = crossing->x;
1196 n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
1197 n_x = fmod (n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
1198
1199 window = gtk_widget_get_window (GTK_WIDGET (item->canvas));
1200
1201 if (crossing->y >= E_REFLOW_BORDER_WIDTH && crossing->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER) {
1202 if (reflow->default_cursor_shown) {
1203 gdk_window_set_cursor (window, reflow->arrow_cursor);
1204 reflow->default_cursor_shown = FALSE;
1205 }
1206 }
1207 }
1208 break;
1209 case GDK_LEAVE_NOTIFY:
1210 if (!reflow->column_drag) {
1211 GdkEventCrossing *crossing = (GdkEventCrossing *) event;
1212 GdkWindow *window;
1213 gdouble n_x;
1214
1215 n_x = crossing->x;
1216 n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
1217 n_x = fmod (n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
1218
1219 window = gtk_widget_get_window (GTK_WIDGET (item->canvas));
1220
1221 if (!(crossing->y >= E_REFLOW_BORDER_WIDTH && crossing->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER)) {
1222 if (!reflow->default_cursor_shown) {
1223 gdk_window_set_cursor (window, reflow->default_cursor);
1224 reflow->default_cursor_shown = TRUE;
1225 }
1226 }
1227 }
1228 break;
1229 default:
1230 break;
1231 }
1232 if (return_val)
1233 return return_val;
1234 else if (GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->event)
1235 return (* GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->event) (item, event);
1236 else
1237 return FALSE;
1238 }
1239
1240 static void
1241 e_reflow_draw (GnomeCanvasItem *item,
1242 cairo_t *cr,
1243 gint x,
1244 gint y,
1245 gint width,
1246 gint height)
1247 {
1248 GtkStyle *style;
1249 gint x_rect, y_rect, width_rect, height_rect;
1250 gdouble running_width;
1251 EReflow *reflow = E_REFLOW (item);
1252 gint i;
1253 gdouble column_width;
1254
1255 if (GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->draw)
1256 GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->draw (item, cr, x, y, width, height);
1257 column_width = reflow->column_width;
1258 running_width = E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
1259 y_rect = E_REFLOW_BORDER_WIDTH;
1260 width_rect = E_REFLOW_DIVIDER_WIDTH;
1261 height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
1262
1263 /* Compute first column to draw. */
1264 i = x;
1265 i /= column_width + E_REFLOW_FULL_GUTTER;
1266 running_width += i * (column_width + E_REFLOW_FULL_GUTTER);
1267
1268 style = gtk_widget_get_style (GTK_WIDGET (item->canvas));
1269
1270 for (; i < reflow->column_count; i++) {
1271 if (running_width > x + width)
1272 break;
1273 x_rect = running_width;
1274 gtk_paint_flat_box (
1275 style,
1276 cr,
1277 GTK_STATE_ACTIVE,
1278 GTK_SHADOW_NONE,
1279 GTK_WIDGET (item->canvas),
1280 "reflow",
1281 x_rect - x,
1282 y_rect - y,
1283 width_rect,
1284 height_rect);
1285 running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
1286 }
1287 if (reflow->column_drag) {
1288 GtkAdjustment *adjustment;
1289 GtkLayout *layout;
1290 gdouble value;
1291 gint start_line;
1292
1293 layout = GTK_LAYOUT (item->canvas);
1294 adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (layout));
1295 value = gtk_adjustment_get_value (adjustment);
1296
1297 start_line = e_reflow_pick_line (reflow, value);
1298 i = x - start_line * (column_width + E_REFLOW_FULL_GUTTER);
1299 running_width = start_line * (column_width + E_REFLOW_FULL_GUTTER);
1300 column_width = reflow->temp_column_width;
1301 running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER);
1302 i += start_line * (column_width + E_REFLOW_FULL_GUTTER);
1303 running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
1304 y_rect = E_REFLOW_BORDER_WIDTH;
1305 width_rect = E_REFLOW_DIVIDER_WIDTH;
1306 height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
1307
1308 /* Compute first column to draw. */
1309 i /= column_width + E_REFLOW_FULL_GUTTER;
1310 running_width += i * (column_width + E_REFLOW_FULL_GUTTER);
1311
1312 cairo_save (cr);
1313 gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
1314
1315 for (; i < reflow->column_count; i++) {
1316 if (running_width > x + width)
1317 break;
1318 x_rect = running_width;
1319 cairo_rectangle (
1320 cr,
1321 x_rect - x,
1322 y_rect - y,
1323 width_rect - 1,
1324 height_rect - 1);
1325 cairo_fill (cr);
1326 running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
1327 }
1328 cairo_restore (cr);
1329 }
1330 }
1331
1332 static void
1333 e_reflow_update (GnomeCanvasItem *item,
1334 const cairo_matrix_t *i2c,
1335 gint flags)
1336 {
1337 EReflow *reflow;
1338 gdouble x0, x1, y0, y1;
1339
1340 reflow = E_REFLOW (item);
1341
1342 if (GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->update)
1343 GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->update (item, i2c, flags);
1344
1345 x0 = item->x1;
1346 y0 = item->y1;
1347 x1 = item->x2;
1348 y1 = item->y2;
1349 if (x1 < x0 + reflow->width)
1350 x1 = x0 + reflow->width;
1351 if (y1 < y0 + reflow->height)
1352 y1 = y0 + reflow->height;
1353 item->x2 = x1;
1354 item->y2 = y1;
1355
1356 if (reflow->need_height_update) {
1357 x0 = item->x1;
1358 y0 = item->y1;
1359 x1 = item->x2;
1360 y1 = item->y2;
1361 if (x0 > 0)
1362 x0 = 0;
1363 if (y0 > 0)
1364 y0 = 0;
1365 if (x1 < E_REFLOW (item)->width)
1366 x1 = E_REFLOW (item)->width;
1367 if (x1 < E_REFLOW (item)->height)
1368 x1 = E_REFLOW (item)->height;
1369
1370 gnome_canvas_request_redraw (item->canvas, x0, y0, x1, y1);
1371 reflow->need_height_update = FALSE;
1372 } else if (reflow->need_column_resize) {
1373 GtkLayout *layout;
1374 GtkAdjustment *adjustment;
1375 gint x_rect, y_rect, width_rect, height_rect;
1376 gint start_line;
1377 gdouble running_width;
1378 gint i;
1379 gdouble column_width;
1380 gdouble value;
1381
1382 layout = GTK_LAYOUT (item->canvas);
1383 adjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (layout));
1384 value = gtk_adjustment_get_value (adjustment);
1385 start_line = e_reflow_pick_line (reflow, value);
1386
1387 if (reflow->previous_temp_column_width != -1) {
1388 running_width = start_line * (reflow->column_width + E_REFLOW_FULL_GUTTER);
1389 column_width = reflow->previous_temp_column_width;
1390 running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER);
1391 running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
1392 y_rect = E_REFLOW_BORDER_WIDTH;
1393 width_rect = E_REFLOW_DIVIDER_WIDTH;
1394 height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
1395
1396 for (i = 0; i < reflow->column_count; i++) {
1397 x_rect = running_width;
1398 gnome_canvas_request_redraw (item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect);
1399 running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
1400 }
1401 }
1402
1403 if (reflow->temp_column_width != -1) {
1404 running_width = start_line * (reflow->column_width + E_REFLOW_FULL_GUTTER);
1405 column_width = reflow->temp_column_width;
1406 running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER);
1407 running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
1408 y_rect = E_REFLOW_BORDER_WIDTH;
1409 width_rect = E_REFLOW_DIVIDER_WIDTH;
1410 height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
1411
1412 for (i = 0; i < reflow->column_count; i++) {
1413 x_rect = running_width;
1414 gnome_canvas_request_redraw (item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect);
1415 running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
1416 }
1417 }
1418
1419 reflow->previous_temp_column_width = reflow->temp_column_width;
1420 reflow->need_column_resize = FALSE;
1421 }
1422 }
1423
1424 static GnomeCanvasItem *
1425 e_reflow_point (GnomeCanvasItem *item,
1426 gdouble x,
1427 gdouble y,
1428 gint cx,
1429 gint cy)
1430 {
1431 GnomeCanvasItem *child = NULL;
1432
1433 if (GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->point)
1434 child = GNOME_CANVAS_ITEM_CLASS (e_reflow_parent_class)->point (item, x, y, cx, cy);
1435
1436 return child ? child : item;
1437 #if 0
1438 if (y >= E_REFLOW_BORDER_WIDTH && y <= reflow->height - E_REFLOW_BORDER_WIDTH) {
1439 gfloat n_x;
1440 n_x = x;
1441 n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
1442 n_x = fmod (n_x, (reflow->column_width + E_REFLOW_FULL_GUTTER));
1443 if (n_x < E_REFLOW_FULL_GUTTER) {
1444 *actual_item = item;
1445 return 0;
1446 }
1447 }
1448 return distance;
1449 #endif
1450 }
1451
1452 static void
1453 e_reflow_reflow (GnomeCanvasItem *item,
1454 gint flags)
1455 {
1456 EReflow *reflow = E_REFLOW (item);
1457 gdouble old_width;
1458 gdouble running_width;
1459 gdouble running_height;
1460 gint next_column;
1461 gint i;
1462
1463 if (!(item->flags & GNOME_CANVAS_ITEM_REALIZED))
1464 return;
1465
1466 if (reflow->need_reflow_columns) {
1467 reflow_columns (reflow);
1468 }
1469
1470 old_width = reflow->width;
1471
1472 running_width = E_REFLOW_BORDER_WIDTH;
1473 running_height = E_REFLOW_BORDER_WIDTH;
1474
1475 next_column = 1;
1476
1477 for (i = 0; i < reflow->count; i++) {
1478 gint unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
1479 if (next_column < reflow->column_count && i == reflow->columns[next_column]) {
1480 running_height = E_REFLOW_BORDER_WIDTH;
1481 running_width += reflow->column_width + E_REFLOW_FULL_GUTTER;
1482 next_column++;
1483 }
1484
1485 if (unsorted >= 0 && reflow->items[unsorted]) {
1486 e_canvas_item_move_absolute (
1487 GNOME_CANVAS_ITEM (reflow->items[unsorted]),
1488 (gdouble) running_width,
1489 (gdouble) running_height);
1490 running_height += reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH;
1491 }
1492 }
1493 reflow->width = running_width + reflow->column_width + E_REFLOW_BORDER_WIDTH;
1494 if (reflow->width < reflow->minimum_width)
1495 reflow->width = reflow->minimum_width;
1496 if (old_width != reflow->width)
1497 e_canvas_item_request_parent_reflow (item);
1498 }
1499
1500 static gint
1501 e_reflow_selection_event_real (EReflow *reflow,
1502 GnomeCanvasItem *item,
1503 GdkEvent *event)
1504 {
1505 gint row;
1506 gint return_val = TRUE;
1507 switch (event->type) {
1508 case GDK_BUTTON_PRESS:
1509 switch (event->button.button) {
1510 case 1: /* Fall through. */
1511 case 2:
1512 row = er_find_item (reflow, item);
1513 if (event->button.button == 1) {
1514 reflow->maybe_did_something =
1515 e_selection_model_maybe_do_something (reflow->selection, row, 0, event->button.state);
1516 reflow->maybe_in_drag = TRUE;
1517 } else {
1518 e_selection_model_do_something (reflow->selection, row, 0, event->button.state);
1519 }
1520 break;
1521 case 3:
1522 row = er_find_item (reflow, item);
1523 e_selection_model_right_click_down (reflow->selection, row, 0, 0);
1524 break;
1525 default:
1526 return_val = FALSE;
1527 break;
1528 }
1529 break;
1530 case GDK_BUTTON_RELEASE:
1531 if (event->button.button == 1) {
1532 if (reflow->maybe_in_drag) {
1533 reflow->maybe_in_drag = FALSE;
1534 if (!reflow->maybe_did_something) {
1535 row = er_find_item (reflow, item);
1536 e_selection_model_do_something (reflow->selection, row, 0, event->button.state);
1537 }
1538 }
1539 }
1540 break;
1541 case GDK_KEY_PRESS:
1542 return_val = e_selection_model_key_press (reflow->selection, (GdkEventKey *) event);
1543 break;
1544 default:
1545 return_val = FALSE;
1546 break;
1547 }
1548
1549 return return_val;
1550 }
1551
1552 static void
1553 e_reflow_class_init (EReflowClass *class)
1554 {
1555 GObjectClass *object_class;
1556 GnomeCanvasItemClass *item_class;
1557
1558 object_class = (GObjectClass *) class;
1559 item_class = (GnomeCanvasItemClass *) class;
1560
1561 object_class->set_property = e_reflow_set_property;
1562 object_class->get_property = e_reflow_get_property;
1563 object_class->dispose = e_reflow_dispose;
1564
1565 /* GnomeCanvasItem method overrides */
1566 item_class->event = e_reflow_event;
1567 item_class->realize = e_reflow_realize;
1568 item_class->unrealize = e_reflow_unrealize;
1569 item_class->draw = e_reflow_draw;
1570 item_class->update = e_reflow_update;
1571 item_class->point = e_reflow_point;
1572
1573 class->selection_event = e_reflow_selection_event_real;
1574 class->column_width_changed = NULL;
1575
1576 g_object_class_install_property (
1577 object_class,
1578 PROP_MINIMUM_WIDTH,
1579 g_param_spec_double (
1580 "minimum_width",
1581 "Minimum width",
1582 "Minimum Width",
1583 0.0, G_MAXDOUBLE, 0.0,
1584 G_PARAM_READWRITE));
1585
1586 g_object_class_install_property (
1587 object_class,
1588 PROP_WIDTH,
1589 g_param_spec_double (
1590 "width",
1591 "Width",
1592 "Width",
1593 0.0, G_MAXDOUBLE, 0.0,
1594 G_PARAM_READABLE));
1595
1596 g_object_class_install_property (
1597 object_class,
1598 PROP_HEIGHT,
1599 g_param_spec_double (
1600 "height",
1601 "Height",
1602 "Height",
1603 0.0, G_MAXDOUBLE, 0.0,
1604 G_PARAM_READWRITE));
1605
1606 g_object_class_install_property (
1607 object_class,
1608 PROP_EMPTY_MESSAGE,
1609 g_param_spec_string (
1610 "empty_message",
1611 "Empty message",
1612 "Empty message",
1613 NULL,
1614 G_PARAM_READWRITE));
1615
1616 g_object_class_install_property (
1617 object_class,
1618 PROP_MODEL,
1619 g_param_spec_object (
1620 "model",
1621 "Reflow model",
1622 "Reflow model",
1623 E_TYPE_REFLOW_MODEL,
1624 G_PARAM_READWRITE));
1625
1626 g_object_class_install_property (
1627 object_class,
1628 PROP_COLUMN_WIDTH,
1629 g_param_spec_double (
1630 "column_width",
1631 "Column width",
1632 "Column width",
1633 0.0, G_MAXDOUBLE, 150.0,
1634 G_PARAM_READWRITE));
1635
1636 signals[SELECTION_EVENT] = g_signal_new (
1637 "selection_event",
1638 G_OBJECT_CLASS_TYPE (object_class),
1639 G_SIGNAL_RUN_LAST,
1640 G_STRUCT_OFFSET (EReflowClass, selection_event),
1641 NULL, NULL,
1642 e_marshal_INT__OBJECT_BOXED,
1643 G_TYPE_INT, 2,
1644 G_TYPE_OBJECT,
1645 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
1646
1647 signals[COLUMN_WIDTH_CHANGED] = g_signal_new (
1648 "column_width_changed",
1649 G_OBJECT_CLASS_TYPE (object_class),
1650 G_SIGNAL_RUN_LAST,
1651 G_STRUCT_OFFSET (EReflowClass, column_width_changed),
1652 NULL, NULL,
1653 g_cclosure_marshal_VOID__DOUBLE,
1654 G_TYPE_NONE, 1,
1655 G_TYPE_DOUBLE);
1656 }
1657
1658 static void
1659 e_reflow_init (EReflow *reflow)
1660 {
1661 reflow->model = NULL;
1662 reflow->items = NULL;
1663 reflow->heights = NULL;
1664 reflow->count = 0;
1665
1666 reflow->columns = NULL;
1667 reflow->column_count = 0;
1668
1669 reflow->empty_text = NULL;
1670 reflow->empty_message = NULL;
1671
1672 reflow->minimum_width = 10;
1673 reflow->width = 10;
1674 reflow->height = 10;
1675
1676 reflow->column_width = 150;
1677
1678 reflow->column_drag = FALSE;
1679
1680 reflow->need_height_update = FALSE;
1681 reflow->need_column_resize = FALSE;
1682 reflow->need_reflow_columns = FALSE;
1683
1684 reflow->maybe_did_something = FALSE;
1685 reflow->maybe_in_drag = FALSE;
1686
1687 reflow->default_cursor_shown = TRUE;
1688 reflow->arrow_cursor = NULL;
1689 reflow->default_cursor = NULL;
1690
1691 reflow->cursor_row = -1;
1692
1693 reflow->incarnate_idle_id = 0;
1694 reflow->do_adjustment_idle_id = 0;
1695 reflow->set_scroll_adjustments_id = 0;
1696
1697 reflow->selection = E_SELECTION_MODEL (e_selection_model_simple_new ());
1698 reflow->sorter = e_sorter_array_new (er_create_cmp_cache, er_compare, reflow);
1699
1700 g_object_set (
1701 reflow->selection,
1702 "sorter", reflow->sorter,
1703 NULL);
1704
1705 reflow->selection_changed_id = g_signal_connect (
1706 reflow->selection, "selection_changed",
1707 G_CALLBACK (selection_changed), reflow);
1708
1709 reflow->selection_row_changed_id = g_signal_connect (
1710 reflow->selection, "selection_row_changed",
1711 G_CALLBACK (selection_row_changed), reflow);
1712
1713 reflow->cursor_changed_id = g_signal_connect (
1714 reflow->selection, "cursor_changed",
1715 G_CALLBACK (cursor_changed), reflow);
1716
1717 e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM (reflow), e_reflow_reflow);
1718 }