No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | e-memo-table.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-memo-table.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
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 * Damon Chaplin <damon@ximian.com>
18 * Rodrigo Moya <rodrigo@ximian.com>
19 * Nathan Owens <pianocomp81@yahoo.com>
20 *
21 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
22 *
23 */
24
25 /*
26 * EMemoTable - displays the ECalComponent objects in a table (an ETable).
27 */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <glib/gi18n.h>
36 #include <glib/gstdio.h>
37 #include <misc/e-selectable.h>
38 #include <table/e-cell-checkbox.h>
39 #include <table/e-cell-toggle.h>
40 #include <table/e-cell-text.h>
41 #include <table/e-cell-combo.h>
42 #include <table/e-cell-date.h>
43 #include <e-util/e-selection.h>
44 #include <e-util/e-dialog-utils.h>
45 #include <e-util/e-util-private.h>
46 #include <table/e-cell-date-edit.h>
47 #include <table/e-cell-percent.h>
48
49 #include "dialogs/delete-comp.h"
50 #include "dialogs/delete-error.h"
51 #include "dialogs/memo-editor.h"
52 #include "e-cal-model-memos.h"
53 #include "e-memo-table.h"
54 #include "e-calendar-view.h"
55 #include "e-cell-date-edit-text.h"
56 #include "print.h"
57 #include <e-util/e-util-private.h>
58 #include <e-util/e-icon-factory.h>
59 #include "misc.h"
60
61 #define E_MEMO_TABLE_GET_PRIVATE(obj) \
62 (G_TYPE_INSTANCE_GET_PRIVATE \
63 ((obj), E_TYPE_MEMO_TABLE, EMemoTablePrivate))
64
65 struct _EMemoTablePrivate {
66 gpointer shell_view; /* weak pointer */
67 ECalModel *model;
68
69 GtkTargetList *copy_target_list;
70 GtkTargetList *paste_target_list;
71 };
72
73 enum {
74 PROP_0,
75 PROP_COPY_TARGET_LIST,
76 PROP_MODEL,
77 PROP_PASTE_TARGET_LIST,
78 PROP_SHELL_VIEW
79 };
80
81 enum {
82 OPEN_COMPONENT,
83 POPUP_EVENT,
84 STATUS_MESSAGE,
85 LAST_SIGNAL
86 };
87
88 static guint signals[LAST_SIGNAL];
89
90 /* The icons to represent the task. */
91 static const gchar *icon_names[] = {
92 "stock_notes",
93 "stock_insert-note"
94 };
95
96 /* Forward Declarations */
97 static void e_memo_table_selectable_init
98 (ESelectableInterface *interface);
99
100 G_DEFINE_TYPE_WITH_CODE (
101 EMemoTable,
102 e_memo_table,
103 E_TYPE_TABLE,
104 G_IMPLEMENT_INTERFACE (
105 E_TYPE_SELECTABLE,
106 e_memo_table_selectable_init))
107
108 static void
109 memo_table_emit_open_component (EMemoTable *memo_table,
110 ECalModelComponent *comp_data)
111 {
112 guint signal_id = signals[OPEN_COMPONENT];
113
114 g_signal_emit (memo_table, signal_id, 0, comp_data);
115 }
116
117 static void
118 memo_table_emit_popup_event (EMemoTable *memo_table,
119 GdkEvent *event)
120 {
121 guint signal_id = signals[POPUP_EVENT];
122
123 g_signal_emit (memo_table, signal_id, 0, event);
124 }
125
126 static void
127 memo_table_emit_status_message (EMemoTable *memo_table,
128 const gchar *message,
129 gdouble percent)
130 {
131 guint signal_id = signals[STATUS_MESSAGE];
132
133 g_signal_emit (memo_table, signal_id, 0, message, percent);
134 }
135
136 /* Returns the current time, for the ECellDateEdit items.
137 * FIXME: Should probably use the timezone of the item rather than the
138 * current timezone, though that may be difficult to get from here. */
139 static struct tm
140 memo_table_get_current_time (ECellDateEdit *ecde,
141 gpointer user_data)
142 {
143 EMemoTable *memo_table = user_data;
144 ECalModel *model;
145 icaltimezone *zone;
146 struct tm tmp_tm = { 0 };
147 struct icaltimetype tt;
148
149 /* Get the current timezone. */
150 model = e_memo_table_get_model (memo_table);
151 zone = e_cal_model_get_timezone (model);
152
153 tt = icaltime_from_timet_with_zone (time (NULL), FALSE, zone);
154
155 /* Now copy it to the struct tm and return it. */
156 tmp_tm.tm_year = tt.year - 1900;
157 tmp_tm.tm_mon = tt.month - 1;
158 tmp_tm.tm_mday = tt.day;
159 tmp_tm.tm_hour = tt.hour;
160 tmp_tm.tm_min = tt.minute;
161 tmp_tm.tm_sec = tt.second;
162 tmp_tm.tm_isdst = -1;
163
164 return tmp_tm;
165 }
166
167 static void
168 memo_table_model_cal_view_progress_cb (EMemoTable *memo_table,
169 const gchar *message,
170 gint progress,
171 ECalClientSourceType type)
172 {
173 gdouble percent = (gdouble) progress;
174
175 memo_table_emit_status_message (memo_table, message, percent);
176 }
177
178 static void
179 memo_table_model_cal_view_complete_cb (EMemoTable *memo_table,
180 const GError *error,
181 ECalClientSourceType type)
182 {
183 memo_table_emit_status_message (memo_table, NULL, -1.0);
184 }
185
186 /* Deletes all of the selected components in the table */
187 static void
188 delete_selected_components (EMemoTable *memo_table)
189 {
190 GSList *objs, *l;
191 const gchar *status_message;
192
193 objs = e_memo_table_get_selected (memo_table);
194
195 status_message = _("Deleting selected objects");
196 memo_table_emit_status_message (memo_table, status_message, -1.0);
197
198 for (l = objs; l; l = l->next) {
199 ECalModelComponent *comp_data = (ECalModelComponent *) l->data;
200 GError *error = NULL;
201
202 e_cal_client_remove_object_sync (
203 comp_data->client,
204 icalcomponent_get_uid (comp_data->icalcomp),
205 NULL, CALOBJ_MOD_THIS, NULL, &error);
206 delete_error_dialog (error, E_CAL_COMPONENT_JOURNAL);
207 g_clear_error (&error);
208 }
209
210 memo_table_emit_status_message (memo_table, NULL, -1.0);
211
212 g_slist_free (objs);
213 }
214
215 static void
216 memo_table_set_model (EMemoTable *memo_table,
217 ECalModel *model)
218 {
219 g_return_if_fail (memo_table->priv->model == NULL);
220
221 memo_table->priv->model = g_object_ref (model);
222
223 g_signal_connect_swapped (
224 model, "cal-view-progress",
225 G_CALLBACK (memo_table_model_cal_view_progress_cb),
226 memo_table);
227
228 g_signal_connect_swapped (
229 model, "cal-view-complete",
230 G_CALLBACK (memo_table_model_cal_view_complete_cb),
231 memo_table);
232 }
233
234 static void
235 memo_table_set_shell_view (EMemoTable *memo_table,
236 EShellView *shell_view)
237 {
238 g_return_if_fail (memo_table->priv->shell_view == NULL);
239
240 memo_table->priv->shell_view = shell_view;
241
242 g_object_add_weak_pointer (
243 G_OBJECT (shell_view),
244 &memo_table->priv->shell_view);
245 }
246
247 static void
248 memo_table_set_property (GObject *object,
249 guint property_id,
250 const GValue *value,
251 GParamSpec *pspec)
252 {
253 switch (property_id) {
254 case PROP_MODEL:
255 memo_table_set_model (
256 E_MEMO_TABLE (object),
257 g_value_get_object (value));
258 return;
259
260 case PROP_SHELL_VIEW:
261 memo_table_set_shell_view (
262 E_MEMO_TABLE (object),
263 g_value_get_object (value));
264 return;
265 }
266
267 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
268 }
269
270 static void
271 memo_table_get_property (GObject *object,
272 guint property_id,
273 GValue *value,
274 GParamSpec *pspec)
275 {
276 switch (property_id) {
277 case PROP_COPY_TARGET_LIST:
278 g_value_set_boxed (
279 value, e_memo_table_get_copy_target_list (
280 E_MEMO_TABLE (object)));
281 return;
282
283 case PROP_MODEL:
284 g_value_set_object (
285 value, e_memo_table_get_model (
286 E_MEMO_TABLE (object)));
287 return;
288
289 case PROP_PASTE_TARGET_LIST:
290 g_value_set_boxed (
291 value, e_memo_table_get_paste_target_list (
292 E_MEMO_TABLE (object)));
293 return;
294
295 case PROP_SHELL_VIEW:
296 g_value_set_object (
297 value, e_memo_table_get_shell_view (
298 E_MEMO_TABLE (object)));
299 return;
300 }
301
302 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
303 }
304
305 static void
306 memo_table_dispose (GObject *object)
307 {
308 EMemoTablePrivate *priv;
309
310 priv = E_MEMO_TABLE_GET_PRIVATE (object);
311
312 if (priv->shell_view != NULL) {
313 g_object_remove_weak_pointer (
314 G_OBJECT (priv->shell_view), &priv->shell_view);
315 priv->shell_view = NULL;
316 }
317
318 if (priv->model != NULL) {
319 g_object_unref (priv->model);
320 priv->model = NULL;
321 }
322
323 if (priv->copy_target_list != NULL) {
324 gtk_target_list_unref (priv->copy_target_list);
325 priv->copy_target_list = NULL;
326 }
327
328 if (priv->paste_target_list != NULL) {
329 gtk_target_list_unref (priv->paste_target_list);
330 priv->paste_target_list = NULL;
331 }
332
333 /* Chain up to parent's dispose() method. */
334 G_OBJECT_CLASS (e_memo_table_parent_class)->dispose (object);
335 }
336
337 static void
338 memo_table_constructed (GObject *object)
339 {
340 EMemoTable *memo_table;
341 ECalModel *model;
342 ECell *cell, *popup_cell;
343 ETableExtras *extras;
344 AtkObject *a11y;
345 gchar *etspecfile;
346
347 memo_table = E_MEMO_TABLE (object);
348 model = e_memo_table_get_model (memo_table);
349
350 /* Create the header columns */
351
352 extras = e_table_extras_new ();
353
354 /*
355 * Normal string fields.
356 */
357 cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
358 g_object_set (cell, "bg_color_column", E_CAL_MODEL_FIELD_COLOR, NULL);
359 e_table_extras_add_cell (extras, "calstring", cell);
360 g_object_unref (cell);
361
362 /*
363 * Date fields.
364 */
365 cell = e_cell_date_edit_text_new (NULL, GTK_JUSTIFY_LEFT);
366 g_object_set (cell, "bg_color_column", E_CAL_MODEL_FIELD_COLOR, NULL);
367
368 g_object_bind_property (
369 model, "timezone",
370 cell, "timezone",
371 G_BINDING_BIDIRECTIONAL |
372 G_BINDING_SYNC_CREATE);
373
374 g_object_bind_property (
375 model, "use-24-hour-format",
376 cell, "use-24-hour-format",
377 G_BINDING_BIDIRECTIONAL |
378 G_BINDING_SYNC_CREATE);
379
380 popup_cell = e_cell_date_edit_new ();
381 e_cell_popup_set_child (E_CELL_POPUP (popup_cell), cell);
382 g_object_unref (cell);
383
384 g_object_bind_property (
385 model, "use-24-hour-format",
386 popup_cell, "use-24-hour-format",
387 G_BINDING_BIDIRECTIONAL |
388 G_BINDING_SYNC_CREATE);
389
390 e_table_extras_add_cell (extras, "dateedit", popup_cell);
391 g_object_unref (popup_cell);
392 memo_table->dates_cell = E_CELL_DATE_EDIT (popup_cell);
393
394 e_cell_date_edit_set_get_time_callback (
395 E_CELL_DATE_EDIT (popup_cell),
396 memo_table_get_current_time, memo_table, NULL);
397
398 /* Sorting */
399 e_table_extras_add_compare (
400 extras, "date-compare", e_cell_date_edit_compare_cb);
401
402 /* Create pixmaps */
403
404 cell = e_cell_toggle_new (icon_names, G_N_ELEMENTS (icon_names));
405 e_table_extras_add_cell (extras, "icon", cell);
406 g_object_unref (cell);
407
408 e_table_extras_add_icon_name (extras, "icon", "stock_notes");
409
410 /* set proper format component for a default 'date' cell renderer */
411 cell = e_table_extras_get_cell (extras, "date");
412 e_cell_date_set_format_component (E_CELL_DATE (cell), "calendar");
413
414 /* set proper format component for a default 'date' cell renderer */
415 cell = e_table_extras_get_cell (extras, "date");
416 e_cell_date_set_format_component (E_CELL_DATE (cell), "calendar");
417
418 /* Construct the table */
419
420 etspecfile = g_build_filename (
421 EVOLUTION_ETSPECDIR, "e-memo-table.etspec", NULL);
422 e_table_construct_from_spec_file (
423 E_TABLE (memo_table), E_TABLE_MODEL (model),
424 extras, etspecfile, NULL);
425 g_free (etspecfile);
426
427 gtk_widget_set_has_tooltip (GTK_WIDGET (memo_table), TRUE);
428
429 g_object_unref (extras);
430
431 a11y = gtk_widget_get_accessible (GTK_WIDGET (memo_table));
432 if (a11y)
433 atk_object_set_name (a11y, _("Memos"));
434
435 /* Chain up to parent's constructed() method. */
436 G_OBJECT_CLASS (e_memo_table_parent_class)->constructed (object);
437 }
438
439 static gboolean
440 memo_table_popup_menu (GtkWidget *widget)
441 {
442 EMemoTable *memo_table;
443
444 memo_table = E_MEMO_TABLE (widget);
445 memo_table_emit_popup_event (memo_table, NULL);
446
447 return TRUE;
448 }
449
450 static gboolean
451 memo_table_query_tooltip (GtkWidget *widget,
452 gint x,
453 gint y,
454 gboolean keyboard_mode,
455 GtkTooltip *tooltip)
456 {
457 EMemoTable *memo_table;
458 ECalModel *model;
459 ECalModelComponent *comp_data;
460 gint row = -1, col = -1;
461 GtkWidget *box, *l, *w;
462 GtkStyle *style = gtk_widget_get_default_style ();
463 gchar *tmp;
464 const gchar *str;
465 GString *tmp2;
466 gchar buff[1001];
467 gboolean free_text = FALSE;
468 gboolean use_24_hour_format;
469 ECalComponent *new_comp;
470 ECalComponentOrganizer organizer;
471 ECalComponentDateTime dtstart, dtdue;
472 icalcomponent *clone;
473 icaltimezone *zone, *default_zone;
474 GSList *desc, *p;
475 gint len;
476 ESelectionModel *esm;
477 struct tm tmp_tm;
478
479 if (keyboard_mode)
480 return FALSE;
481
482 memo_table = E_MEMO_TABLE (widget);
483
484 e_table_get_mouse_over_cell (E_TABLE (memo_table), &row, &col);
485 if (row == -1)
486 return FALSE;
487
488 /* Respect sorting option; the 'e_table_get_mouse_over_cell'
489 * returns sorted row, not the model one. */
490 esm = e_table_get_selection_model (E_TABLE (memo_table));
491 if (esm && esm->sorter && e_sorter_needs_sorting (esm->sorter))
492 row = e_sorter_sorted_to_model (esm->sorter, row);
493
494 model = e_memo_table_get_model (memo_table);
495 comp_data = e_cal_model_get_component_at (model, row);
496 if (!comp_data || !comp_data->icalcomp)
497 return FALSE;
498
499 new_comp = e_cal_component_new ();
500 clone = icalcomponent_new_clone (comp_data->icalcomp);
501 if (!e_cal_component_set_icalcomponent (new_comp, clone)) {
502 g_object_unref (new_comp);
503 return FALSE;
504 }
505
506 box = gtk_vbox_new (FALSE, 0);
507
508 str = e_calendar_view_get_icalcomponent_summary (
509 comp_data->client, comp_data->icalcomp, &free_text);
510 if (!(str && *str)) {
511 if (free_text)
512 g_free ((gchar *) str);
513 free_text = FALSE;
514 str = _("* No Summary *");
515 }
516
517 l = gtk_label_new (NULL);
518 tmp = g_markup_printf_escaped ("<b>%s</b>", str);
519 gtk_label_set_line_wrap (GTK_LABEL (l), TRUE);
520 gtk_label_set_markup (GTK_LABEL (l), tmp);
521 gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
522 w = gtk_event_box_new ();
523
524 gtk_widget_modify_bg (w, GTK_STATE_NORMAL, &(style->bg[GTK_STATE_SELECTED]));
525 gtk_widget_modify_fg (l, GTK_STATE_NORMAL, &(style->text[GTK_STATE_SELECTED]));
526 gtk_container_add (GTK_CONTAINER (w), l);
527 gtk_box_pack_start (GTK_BOX (box), w, TRUE, TRUE, 0);
528 g_free (tmp);
529
530 if (free_text)
531 g_free ((gchar *) str);
532 free_text = FALSE;
533
534 w = gtk_event_box_new ();
535 gtk_widget_modify_bg (w, GTK_STATE_NORMAL, &(style->bg[GTK_STATE_NORMAL]));
536
537 l = gtk_vbox_new (FALSE, 0);
538 gtk_container_add (GTK_CONTAINER (w), l);
539 gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
540 w = l;
541
542 e_cal_component_get_organizer (new_comp, &organizer);
543 if (organizer.cn) {
544 gchar *ptr;
545 ptr = strchr (organizer.value, ':');
546
547 if (ptr) {
548 ptr++;
549 /* Translators: It will display
550 * "Organizer: NameOfTheUser <email@ofuser.com>" */
551 tmp = g_strdup_printf (
552 _("Organizer: %s <%s>"), organizer.cn, ptr);
553 } else {
554 /* With SunOne accounts, there may be no ':' in
555 * organizer.value */
556 tmp = g_strdup_printf (
557 _("Organizer: %s"), organizer.cn);
558 }
559
560 l = gtk_label_new (tmp);
561 gtk_label_set_line_wrap (GTK_LABEL (l), FALSE);
562 gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
563 gtk_box_pack_start (GTK_BOX (w), l, FALSE, FALSE, 0);
564 g_free (tmp);
565
566 gtk_widget_modify_fg (l, GTK_STATE_NORMAL, &(style->text[GTK_STATE_NORMAL]));
567 }
568
569 e_cal_component_get_dtstart (new_comp, &dtstart);
570 e_cal_component_get_due (new_comp, &dtdue);
571
572 default_zone = e_cal_model_get_timezone (model);
573
574 if (dtstart.tzid) {
575 zone = icalcomponent_get_timezone (
576 e_cal_component_get_icalcomponent (new_comp),
577 dtstart.tzid);
578 if (!zone)
579 e_cal_client_get_timezone_sync (
580 comp_data->client, dtstart.tzid, &zone, NULL, NULL);
581 if (!zone)
582 zone = default_zone;
583 } else {
584 zone = NULL;
585 }
586
587 tmp2 = g_string_new ("");
588 use_24_hour_format = e_cal_model_get_use_24_hour_format (model);
589
590 if (dtstart.value) {
591 buff[0] = 0;
592
593 tmp_tm = icaltimetype_to_tm_with_zone (
594 dtstart.value, zone, default_zone);
595 e_time_format_date_and_time (
596 &tmp_tm, use_24_hour_format,
597 FALSE, FALSE, buff, 1000);
598
599 if (buff[0]) {
600 /* Translators: This is followed by an event's start date/time */
601 g_string_append (tmp2, _("Start: "));
602 g_string_append (tmp2, buff);
603 }
604 }
605
606 if (dtdue.value) {
607 buff[0] = 0;
608
609 tmp_tm = icaltimetype_to_tm_with_zone (
610 dtdue.value, zone, default_zone);
611 e_time_format_date_and_time (
612 &tmp_tm, use_24_hour_format,
613 FALSE, FALSE, buff, 1000);
614
615 if (buff[0]) {
616 if (tmp2->len)
617 g_string_append (tmp2, "; ");
618
619 /* Translators: This is followed by an event's due date/time */
620 g_string_append (tmp2, _("Due: "));
621 g_string_append (tmp2, buff);
622 }
623 }
624
625 if (tmp2->len) {
626 l = gtk_label_new (tmp2->str);
627 gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
628 gtk_box_pack_start (GTK_BOX (w), l, FALSE, FALSE, 0);
629
630 gtk_widget_modify_fg (l, GTK_STATE_NORMAL, &(style->text[GTK_STATE_NORMAL]));
631 }
632
633 g_string_free (tmp2, TRUE);
634
635 e_cal_component_free_datetime (&dtstart);
636 e_cal_component_free_datetime (&dtdue);
637
638 tmp2 = g_string_new ("");
639 e_cal_component_get_description_list (new_comp, &desc);
640 for (len = 0, p = desc; p != NULL; p = p->next) {
641 ECalComponentText *text = p->data;
642
643 if (text->value != NULL) {
644 len += strlen (text->value);
645 g_string_append (tmp2, text->value);
646 if (len > 1024) {
647 g_string_set_size (tmp2, 1020);
648 g_string_append (tmp2, "...");
649 break;
650 }
651 }
652 }
653 e_cal_component_free_text_list (desc);
654
655 if (tmp2->len) {
656 l = gtk_label_new (tmp2->str);
657 gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
658 gtk_box_pack_start (GTK_BOX (w), l, FALSE, FALSE, 0);
659
660 gtk_widget_modify_fg (l, GTK_STATE_NORMAL, &(style->text[GTK_STATE_NORMAL]));
661 }
662
663 g_string_free (tmp2, TRUE);
664
665 gtk_widget_show_all (box);
666 gtk_tooltip_set_custom (tooltip, box);
667
668 g_object_unref (new_comp);
669
670 return TRUE;
671 }
672
673 static void
674 memo_table_double_click (ETable *table,
675 gint row,
676 gint col,
677 GdkEvent *event)
678 {
679 EMemoTable *memo_table;
680 ECalModel *model;
681 ECalModelComponent *comp_data;
682
683 memo_table = E_MEMO_TABLE (table);
684 model = e_memo_table_get_model (memo_table);
685 comp_data = e_cal_model_get_component_at (model, row);
686 memo_table_emit_open_component (memo_table, comp_data);
687 }
688
689 static gint
690 memo_table_right_click (ETable *table,
691 gint row,
692 gint col,
693 GdkEvent *event)
694 {
695 EMemoTable *memo_table;
696
697 memo_table = E_MEMO_TABLE (table);
698 memo_table_emit_popup_event (memo_table, event);
699
700 return TRUE;
701 }
702
703 static void
704 memo_table_update_actions (ESelectable *selectable,
705 EFocusTracker *focus_tracker,
706 GdkAtom *clipboard_targets,
707 gint n_clipboard_targets)
708 {
709 EMemoTable *memo_table;
710 GtkAction *action;
711 GtkTargetList *target_list;
712 GSList *list, *iter;
713 gboolean can_paste = FALSE;
714 gboolean sources_are_editable = TRUE;
715 gboolean sensitive;
716 const gchar *tooltip;
717 gint n_selected;
718 gint ii;
719
720 memo_table = E_MEMO_TABLE (selectable);
721 n_selected = e_table_selected_count (E_TABLE (memo_table));
722
723 list = e_memo_table_get_selected (memo_table);
724 for (iter = list; iter != NULL && sources_are_editable; iter = iter->next) {
725 ECalModelComponent *comp_data = iter->data;
726
727 sources_are_editable = sources_are_editable &&
728 !e_client_is_readonly (E_CLIENT (comp_data->client));
729 }
730 g_slist_free (list);
731
732 target_list = e_selectable_get_paste_target_list (selectable);
733 for (ii = 0; ii < n_clipboard_targets && !can_paste; ii++)
734 can_paste = gtk_target_list_find (
735 target_list, clipboard_targets[ii], NULL);
736
737 action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
738 sensitive = (n_selected > 0) && sources_are_editable;
739 tooltip = _("Cut selected memos to the clipboard");
740 gtk_action_set_sensitive (action, sensitive);
741 gtk_action_set_tooltip (action, tooltip);
742
743 action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
744 sensitive = (n_selected > 0);
745 tooltip = _("Copy selected memos to the clipboard");
746 gtk_action_set_sensitive (action, sensitive);
747 gtk_action_set_tooltip (action, tooltip);
748
749 action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
750 sensitive = sources_are_editable && can_paste;
751 tooltip = _("Paste memos from the clipboard");
752 gtk_action_set_sensitive (action, sensitive);
753 gtk_action_set_tooltip (action, tooltip);
754
755 action = e_focus_tracker_get_delete_selection_action (focus_tracker);
756 sensitive = (n_selected > 0) && sources_are_editable;
757 tooltip = _("Delete selected memos");
758 gtk_action_set_sensitive (action, sensitive);
759 gtk_action_set_tooltip (action, tooltip);
760
761 action = e_focus_tracker_get_select_all_action (focus_tracker);
762 sensitive = TRUE;
763 tooltip = _("Select all visible memos");
764 gtk_action_set_sensitive (action, sensitive);
765 gtk_action_set_tooltip (action, tooltip);
766 }
767
768 static void
769 memo_table_cut_clipboard (ESelectable *selectable)
770 {
771 EMemoTable *memo_table;
772
773 memo_table = E_MEMO_TABLE (selectable);
774
775 e_selectable_copy_clipboard (selectable);
776 delete_selected_components (memo_table);
777 }
778
779 /* Helper for memo_table_copy_clipboard() */
780 static void
781 copy_row_cb (gint model_row,
782 gpointer data)
783 {
784 EMemoTable *memo_table;
785 ECalModelComponent *comp_data;
786 ECalModel *model;
787 gchar *comp_str;
788 icalcomponent *child;
789
790 memo_table = E_MEMO_TABLE (data);
791
792 g_return_if_fail (memo_table->tmp_vcal != NULL);
793
794 model = e_memo_table_get_model (memo_table);
795 comp_data = e_cal_model_get_component_at (model, model_row);
796 if (comp_data == NULL)
797 return;
798
799 /* Add timezones to the VCALENDAR component. */
800 e_cal_util_add_timezones_from_component (
801 memo_table->tmp_vcal, comp_data->icalcomp);
802
803 /* Add the new component to the VCALENDAR component. */
804 comp_str = icalcomponent_as_ical_string_r (comp_data->icalcomp);
805 child = icalparser_parse_string (comp_str);
806 if (child) {
807 icalcomponent_add_component (
808 memo_table->tmp_vcal,
809 icalcomponent_new_clone (child));
810 icalcomponent_free (child);
811 }
812 g_free (comp_str);
813 }
814
815 static void
816 memo_table_copy_clipboard (ESelectable *selectable)
817 {
818 EMemoTable *memo_table;
819 GtkClipboard *clipboard;
820 gchar *comp_str;
821
822 memo_table = E_MEMO_TABLE (selectable);
823
824 /* Create a temporary VCALENDAR object. */
825 memo_table->tmp_vcal = e_cal_util_new_top_level ();
826
827 e_table_selected_row_foreach (
828 E_TABLE (memo_table), copy_row_cb, memo_table);
829 comp_str = icalcomponent_as_ical_string_r (memo_table->tmp_vcal);
830
831 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
832 e_clipboard_set_calendar (clipboard, comp_str, -1);
833 gtk_clipboard_store (clipboard);
834
835 g_free (comp_str);
836
837 icalcomponent_free (memo_table->tmp_vcal);
838 memo_table->tmp_vcal = NULL;
839 }
840
841 /* Helper for memo_table_paste_clipboard() */
842 static void
843 clipboard_get_calendar_data (EMemoTable *memo_table,
844 const gchar *text)
845 {
846 icalcomponent *icalcomp;
847 gchar *uid;
848 ECalComponent *comp;
849 ECalClient *client;
850 ECalModel *model;
851 icalcomponent_kind kind;
852 const gchar *status_message;
853
854 g_return_if_fail (E_IS_MEMO_TABLE (memo_table));
855
856 if (!text || !*text)
857 return;
858
859 icalcomp = icalparser_parse_string (text);
860 if (!icalcomp)
861 return;
862
863 /* check the type of the component */
864 kind = icalcomponent_isa (icalcomp);
865 if (kind != ICAL_VCALENDAR_COMPONENT &&
866 kind != ICAL_VEVENT_COMPONENT &&
867 kind != ICAL_VTODO_COMPONENT &&
868 kind != ICAL_VJOURNAL_COMPONENT) {
869 return;
870 }
871
872 model = e_memo_table_get_model (memo_table);
873 client = e_cal_model_get_default_client (model);
874
875 status_message = _("Updating objects");
876 memo_table_emit_status_message (memo_table, status_message, -1.0);
877
878 if (kind == ICAL_VCALENDAR_COMPONENT) {
879 icalcomponent_kind child_kind;
880 icalcomponent *subcomp;
881 icalcomponent *vcal_comp;
882
883 vcal_comp = icalcomp;
884 subcomp = icalcomponent_get_first_component (
885 vcal_comp, ICAL_ANY_COMPONENT);
886 while (subcomp) {
887 child_kind = icalcomponent_isa (subcomp);
888 if (child_kind == ICAL_VEVENT_COMPONENT ||
889 child_kind == ICAL_VTODO_COMPONENT ||
890 child_kind == ICAL_VJOURNAL_COMPONENT) {
891 ECalComponent *tmp_comp;
892 GError *error = NULL;
893
894 uid = e_cal_component_gen_uid ();
895 tmp_comp = e_cal_component_new ();
896 e_cal_component_set_icalcomponent (
897 tmp_comp,
898 icalcomponent_new_clone (subcomp));
899 e_cal_component_set_uid (tmp_comp, uid);
900 g_free (uid);
901 uid = NULL;
902
903 /* FIXME Should we convert start/due/complete
904 * times? Also, need error handling.*/
905 if (!e_cal_client_create_object_sync (client, e_cal_component_get_icalcomponent (tmp_comp), &uid, NULL, &error))
906 uid = NULL;
907
908 g_free (uid);
909 g_object_unref (tmp_comp);
910
911 if (error != NULL) {
912 g_warning (
913 "%s: Failed to create object: %s",
914 G_STRFUNC, error->message);
915 g_error_free (error);
916 }
917 }
918 subcomp = icalcomponent_get_next_component (
919 vcal_comp, ICAL_ANY_COMPONENT);
920 }
921 } else {
922 GError *error = NULL;
923
924 comp = e_cal_component_new ();
925 e_cal_component_set_icalcomponent (comp, icalcomp);
926 uid = e_cal_component_gen_uid ();
927 e_cal_component_set_uid (comp, (const gchar *) uid);
928 g_free (uid);
929
930 uid = NULL;
931 if (!e_cal_client_create_object_sync (client, e_cal_component_get_icalcomponent (comp), &uid, NULL, &error))
932 uid = NULL;
933
934 g_free (uid);
935 g_object_unref (comp);
936
937 if (error != NULL) {
938 g_warning (
939 "%s: Failed to create object: %s",
940 G_STRFUNC, error->message);
941 g_error_free (error);
942 }
943 }
944
945 memo_table_emit_status_message (memo_table, NULL, -1.0);
946 }
947
948 static void
949 memo_table_paste_clipboard (ESelectable *selectable)
950 {
951 EMemoTable *memo_table;
952 GtkClipboard *clipboard;
953 GnomeCanvasItem *item;
954 GnomeCanvas *table_canvas;
955
956 memo_table = E_MEMO_TABLE (selectable);
957
958 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
959
960 table_canvas = E_TABLE (memo_table)->table_canvas;
961 item = table_canvas->focused_item;
962
963 /* XXX Should ECellText implement GtkEditable? */
964
965 /* Paste text into a cell being edited. */
966 if (gtk_clipboard_wait_is_text_available (clipboard) &&
967 gtk_widget_has_focus (GTK_WIDGET (table_canvas)) &&
968 E_IS_TABLE_ITEM (item) &&
969 E_TABLE_ITEM (item)->editing_col >= 0 &&
970 E_TABLE_ITEM (item)->editing_row >= 0) {
971
972 ETableItem *etable_item = E_TABLE_ITEM (item);
973
974 e_cell_text_paste_clipboard (
975 etable_item->cell_views[etable_item->editing_col],
976 etable_item->editing_col,
977 etable_item->editing_row);
978
979 /* Paste iCalendar data into the table. */
980 } else if (e_clipboard_wait_is_calendar_available (clipboard)) {
981 gchar *calendar_source;
982
983 calendar_source = e_clipboard_wait_for_calendar (clipboard);
984 clipboard_get_calendar_data (memo_table, calendar_source);
985 g_free (calendar_source);
986 }
987 }
988
989 /* Used from e_table_selected_row_foreach(); puts the selected row number in an
990 * gint pointed to by the closure data.
991 */
992 static void
993 get_selected_row_cb (gint model_row,
994 gpointer data)
995 {
996 gint *row;
997
998 row = data;
999 *row = model_row;
1000 }
1001
1002 /*
1003 * Returns the component that is selected in the table; only works if there is
1004 * one and only one selected row.
1005 */
1006 static ECalModelComponent *
1007 get_selected_comp (EMemoTable *memo_table)
1008 {
1009 ECalModel *model;
1010 gint row;
1011
1012 model = e_memo_table_get_model (memo_table);
1013 if (e_table_selected_count (E_TABLE (memo_table)) != 1)
1014 return NULL;
1015
1016 row = -1;
1017 e_table_selected_row_foreach (
1018 E_TABLE (memo_table), get_selected_row_cb, &row);
1019 g_return_val_if_fail (row != -1, NULL);
1020
1021 return e_cal_model_get_component_at (model, row);
1022 }
1023
1024 static void
1025 memo_table_delete_selection (ESelectable *selectable)
1026 {
1027 ECalModel *model;
1028 EMemoTable *memo_table;
1029 ECalComponent *comp = NULL;
1030 ECalModelComponent *comp_data;
1031 gboolean delete = TRUE;
1032 gint n_selected;
1033
1034 memo_table = E_MEMO_TABLE (selectable);
1035 model = e_memo_table_get_model (memo_table);
1036
1037 n_selected = e_table_selected_count (E_TABLE (memo_table));
1038 if (n_selected <= 0)
1039 return;
1040
1041 if (n_selected == 1)
1042 comp_data = get_selected_comp (memo_table);
1043 else
1044 comp_data = NULL;
1045
1046 /* FIXME: this may be something other than a TODO component */
1047
1048 if (comp_data) {
1049 comp = e_cal_component_new ();
1050 e_cal_component_set_icalcomponent (
1051 comp, icalcomponent_new_clone (comp_data->icalcomp));
1052 }
1053
1054 if (e_cal_model_get_confirm_delete (model))
1055 delete = delete_component_dialog (
1056 comp, FALSE, n_selected,
1057 E_CAL_COMPONENT_JOURNAL,
1058 GTK_WIDGET (memo_table));
1059
1060 if (delete)
1061 delete_selected_components (memo_table);
1062
1063 /* free memory */
1064 if (comp)
1065 g_object_unref (comp);
1066 }
1067
1068 static void
1069 memo_table_select_all (ESelectable *selectable)
1070 {
1071 e_table_select_all (E_TABLE (selectable));
1072 }
1073
1074 static void
1075 e_memo_table_class_init (EMemoTableClass *class)
1076 {
1077 GObjectClass *object_class;
1078 GtkWidgetClass *widget_class;
1079 ETableClass *table_class;
1080
1081 g_type_class_add_private (class, sizeof (EMemoTablePrivate));
1082
1083 object_class = G_OBJECT_CLASS (class);
1084 object_class->set_property = memo_table_set_property;
1085 object_class->get_property = memo_table_get_property;
1086 object_class->dispose = memo_table_dispose;
1087 object_class->constructed = memo_table_constructed;
1088
1089 widget_class = GTK_WIDGET_CLASS (class);
1090 widget_class->popup_menu = memo_table_popup_menu;
1091 widget_class->query_tooltip = memo_table_query_tooltip;
1092
1093 table_class = E_TABLE_CLASS (class);
1094 table_class->double_click = memo_table_double_click;
1095 table_class->right_click = memo_table_right_click;
1096
1097 /* Inherited from ESelectableInterface */
1098 g_object_class_override_property (
1099 object_class,
1100 PROP_COPY_TARGET_LIST,
1101 "copy-target-list");
1102
1103 g_object_class_install_property (
1104 object_class,
1105 PROP_MODEL,
1106 g_param_spec_object (
1107 "model",
1108 "Model",
1109 NULL,
1110 E_TYPE_CAL_MODEL,
1111 G_PARAM_READWRITE |
1112 G_PARAM_CONSTRUCT_ONLY));
1113
1114 /* Inherited from ESelectableInterface */
1115 g_object_class_override_property (
1116 object_class,
1117 PROP_PASTE_TARGET_LIST,
1118 "paste-target-list");
1119
1120 g_object_class_install_property (
1121 object_class,
1122 PROP_SHELL_VIEW,
1123 g_param_spec_object (
1124 "shell-view",
1125 "Shell View",
1126 NULL,
1127 E_TYPE_SHELL_VIEW,
1128 G_PARAM_READWRITE |
1129 G_PARAM_CONSTRUCT_ONLY));
1130
1131 signals[OPEN_COMPONENT] = g_signal_new (
1132 "open-component",
1133 G_TYPE_FROM_CLASS (class),
1134 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1135 G_STRUCT_OFFSET (EMemoTableClass, open_component),
1136 NULL, NULL,
1137 g_cclosure_marshal_VOID__OBJECT,
1138 G_TYPE_NONE, 1,
1139 E_TYPE_CAL_MODEL_COMPONENT);
1140
1141 signals[POPUP_EVENT] = g_signal_new (
1142 "popup-event",
1143 G_TYPE_FROM_CLASS (class),
1144 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1145 G_STRUCT_OFFSET (EMemoTableClass, popup_event),
1146 NULL, NULL,
1147 g_cclosure_marshal_VOID__BOXED,
1148 G_TYPE_NONE, 1,
1149 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
1150
1151 signals[STATUS_MESSAGE] = g_signal_new (
1152 "status-message",
1153 G_TYPE_FROM_CLASS (class),
1154 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1155 G_STRUCT_OFFSET (EMemoTableClass, status_message),
1156 NULL, NULL,
1157 e_marshal_VOID__STRING_DOUBLE,
1158 G_TYPE_NONE, 2,
1159 G_TYPE_STRING, G_TYPE_DOUBLE);
1160 }
1161
1162 static void
1163 e_memo_table_init (EMemoTable *memo_table)
1164 {
1165 GtkTargetList *target_list;
1166
1167 memo_table->priv = E_MEMO_TABLE_GET_PRIVATE (memo_table);
1168
1169 target_list = gtk_target_list_new (NULL, 0);
1170 e_target_list_add_calendar_targets (target_list, 0);
1171 memo_table->priv->copy_target_list = target_list;
1172
1173 target_list = gtk_target_list_new (NULL, 0);
1174 e_target_list_add_calendar_targets (target_list, 0);
1175 memo_table->priv->paste_target_list = target_list;
1176 }
1177
1178 static void
1179 e_memo_table_selectable_init (ESelectableInterface *interface)
1180 {
1181 interface->update_actions = memo_table_update_actions;
1182 interface->cut_clipboard = memo_table_cut_clipboard;
1183 interface->copy_clipboard = memo_table_copy_clipboard;
1184 interface->paste_clipboard = memo_table_paste_clipboard;
1185 interface->delete_selection = memo_table_delete_selection;
1186 interface->select_all = memo_table_select_all;
1187 }
1188
1189 /**
1190 * e_memo_table_new:
1191 * @shell_view: an #EShellView
1192 * @model: an #ECalModel for the table
1193 *
1194 * Returns a new #EMemoTable.
1195 *
1196 * Returns: a new #EMemoTable
1197 **/
1198 GtkWidget *
1199 e_memo_table_new (EShellView *shell_view,
1200 ECalModel *model)
1201 {
1202 g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
1203 g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
1204
1205 return g_object_new (
1206 E_TYPE_MEMO_TABLE,
1207 "model", model, "shell-view", shell_view, NULL);
1208 }
1209
1210 /**
1211 * e_memo_table_get_model:
1212 * @memo_table: A calendar table.
1213 *
1214 * Queries the calendar data model that a calendar table is using.
1215 *
1216 * Return value: A memo model.
1217 **/
1218 ECalModel *
1219 e_memo_table_get_model (EMemoTable *memo_table)
1220 {
1221 g_return_val_if_fail (memo_table != NULL, NULL);
1222 g_return_val_if_fail (E_IS_MEMO_TABLE (memo_table), NULL);
1223
1224 return memo_table->priv->model;
1225 }
1226
1227 EShellView *
1228 e_memo_table_get_shell_view (EMemoTable *memo_table)
1229 {
1230 g_return_val_if_fail (E_IS_MEMO_TABLE (memo_table), NULL);
1231
1232 return memo_table->priv->shell_view;
1233 }
1234
1235 struct get_selected_uids_closure {
1236 EMemoTable *memo_table;
1237 GSList *objects;
1238 };
1239
1240 /* Used from e_table_selected_row_foreach(), builds a list of the selected UIDs */
1241 static void
1242 add_uid_cb (gint model_row,
1243 gpointer data)
1244 {
1245 struct get_selected_uids_closure *closure;
1246 ECalModelComponent *comp_data;
1247 ECalModel *model;
1248
1249 closure = data;
1250
1251 model = e_memo_table_get_model (closure->memo_table);
1252 comp_data = e_cal_model_get_component_at (model, model_row);
1253
1254 closure->objects = g_slist_prepend (closure->objects, comp_data);
1255 }
1256
1257 /**
1258 * e_memo_table_get_selected:
1259 * @memo_table:
1260 *
1261 * Get the currently selected ECalModelComponent's on the table.
1262 *
1263 * Return value: A GSList of the components, which should be
1264 * g_slist_free'd when finished with.
1265 **/
1266 GSList *
1267 e_memo_table_get_selected (EMemoTable *memo_table)
1268 {
1269 struct get_selected_uids_closure closure;
1270
1271 closure.memo_table = memo_table;
1272 closure.objects = NULL;
1273
1274 e_table_selected_row_foreach (
1275 E_TABLE (memo_table), add_uid_cb, &closure);
1276
1277 return closure.objects;
1278 }
1279
1280 GtkTargetList *
1281 e_memo_table_get_copy_target_list (EMemoTable *memo_table)
1282 {
1283 g_return_val_if_fail (E_IS_MEMO_TABLE (memo_table), NULL);
1284
1285 return memo_table->priv->copy_target_list;
1286 }
1287
1288 GtkTargetList *
1289 e_memo_table_get_paste_target_list (EMemoTable *memo_table)
1290 {
1291 g_return_val_if_fail (E_IS_MEMO_TABLE (memo_table), NULL);
1292
1293 return memo_table->priv->paste_target_list;
1294 }