No issues found
1 /*
2 * e-cal-shell-content.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 *
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include "e-cal-shell-content.h"
27
28 #include <string.h>
29 #include <glib/gi18n.h>
30
31 #include "widgets/menus/gal-view-etable.h"
32 #include "widgets/misc/e-paned.h"
33 #include "widgets/misc/e-selectable.h"
34
35 #include "calendar/gui/calendar-config.h"
36 #include "calendar/gui/calendar-view.h"
37 #include "calendar/gui/e-cal-list-view.h"
38 #include "calendar/gui/e-cal-model-calendar.h"
39 #include "calendar/gui/e-calendar-view.h"
40 #include "calendar/gui/e-day-view.h"
41 #include "calendar/gui/e-week-view.h"
42
43 #include "e-cal-shell-view-private.h"
44
45 #define E_CAL_SHELL_CONTENT_GET_PRIVATE(obj) \
46 (G_TYPE_INSTANCE_GET_PRIVATE \
47 ((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentPrivate))
48
49 struct _ECalShellContentPrivate {
50 GtkWidget *hpaned;
51 GtkWidget *notebook;
52 GtkWidget *vpaned;
53
54 GtkWidget *calendar;
55 GtkWidget *task_table;
56 GtkWidget *memo_table;
57
58 GalViewInstance *view_instance;
59 };
60
61 enum {
62 PROP_0,
63 PROP_CALENDAR,
64 PROP_MEMO_TABLE,
65 PROP_TASK_TABLE
66 };
67
68 /* Used to indicate who has the focus within the calendar view. */
69 typedef enum {
70 FOCUS_CALENDAR,
71 FOCUS_MEMO_TABLE,
72 FOCUS_TASK_TABLE,
73 FOCUS_OTHER
74 } FocusLocation;
75
76 G_DEFINE_DYNAMIC_TYPE (
77 ECalShellContent,
78 e_cal_shell_content,
79 E_TYPE_SHELL_CONTENT)
80
81 static void
82 cal_shell_content_display_view_cb (ECalShellContent *cal_shell_content,
83 GalView *gal_view)
84 {
85 GnomeCalendar *calendar;
86 GnomeCalendarViewType view_type;
87
88 /* XXX This is confusing: we have CalendarView and ECalendarView.
89 * ECalendarView is an abstract base class for calendar view
90 * widgets (day view, week view, etc). CalendarView is a
91 * simple GalView subclass that represents a calendar view. */
92
93 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
94
95 if (GAL_IS_VIEW_ETABLE (gal_view)) {
96 ECalendarView *calendar_view;
97
98 view_type = GNOME_CAL_LIST_VIEW;
99 calendar_view = gnome_calendar_get_calendar_view (
100 calendar, view_type);
101 gal_view_etable_attach_table (
102 GAL_VIEW_ETABLE (gal_view),
103 E_CAL_LIST_VIEW (calendar_view)->table);
104 } else {
105 view_type = calendar_view_get_view_type (
106 CALENDAR_VIEW (gal_view));
107 }
108
109 gnome_calendar_display_view (calendar, view_type);
110 }
111
112 static void
113 cal_shell_content_notify_view_id_cb (ECalShellContent *cal_shell_content)
114 {
115 EShellContent *shell_content;
116 EShellView *shell_view;
117 GSettings *settings;
118 GtkWidget *paned;
119 const gchar *key;
120 const gchar *view_id;
121
122 settings = g_settings_new ("org.gnome.evolution.calendar");
123 paned = cal_shell_content->priv->hpaned;
124
125 shell_content = E_SHELL_CONTENT (cal_shell_content);
126 shell_view = e_shell_content_get_shell_view (shell_content);
127 view_id = e_shell_view_get_view_id (shell_view);
128
129 if (view_id != NULL && strcmp (view_id, "Month_View") == 0)
130 key = "month-hpane-position";
131 else
132 key = "hpane-position";
133
134 g_settings_unbind (paned, "hposition");
135
136 g_settings_bind (
137 settings, key,
138 paned, "hposition",
139 G_SETTINGS_BIND_DEFAULT);
140
141 g_object_unref (settings);
142 }
143
144 static gchar *
145 cal_shell_content_get_pad_state_filename (EShellContent *shell_content,
146 ETable *table)
147 {
148 EShellBackend *shell_backend;
149 EShellView *shell_view;
150 const gchar *config_dir, *nick = NULL;
151
152 g_return_val_if_fail (shell_content != NULL, NULL);
153 g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
154 g_return_val_if_fail (table != NULL, NULL);
155 g_return_val_if_fail (E_IS_TABLE (table), NULL);
156
157 if (E_IS_TASK_TABLE (table))
158 nick = "TaskPad";
159 else if (E_IS_MEMO_TABLE (table))
160 nick = "MemoPad";
161
162 g_return_val_if_fail (nick != NULL, NULL);
163
164 shell_view = e_shell_content_get_shell_view (shell_content);
165 shell_backend = e_shell_view_get_shell_backend (shell_view);
166 config_dir = e_shell_backend_get_config_dir (shell_backend);
167
168 return g_build_filename (config_dir, nick, NULL);
169 }
170
171 static void
172 cal_shell_content_save_table_state (EShellContent *shell_content,
173 ETable *table)
174 {
175 gchar *filename;
176
177 filename = cal_shell_content_get_pad_state_filename (
178 shell_content, table);
179 g_return_if_fail (filename != NULL);
180
181 e_table_save_state (table, filename);
182 g_free (filename);
183 }
184
185 static void
186 cal_shell_content_load_table_state (EShellContent *shell_content,
187 ETable *table)
188 {
189 gchar *filename;
190
191 filename = cal_shell_content_get_pad_state_filename (
192 shell_content, table);
193 g_return_if_fail (filename != NULL);
194
195 e_table_load_state (table, filename);
196 g_free (filename);
197 }
198
199 void
200 e_cal_shell_content_save_state (ECalShellContent *cal_shell_content)
201 {
202 ECalShellContentPrivate *priv;
203
204 g_return_if_fail (cal_shell_content != NULL);
205 g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
206
207 priv = cal_shell_content->priv;
208
209 if (priv->task_table != NULL)
210 cal_shell_content_save_table_state (
211 E_SHELL_CONTENT (cal_shell_content),
212 E_TABLE (priv->task_table));
213
214 if (priv->memo_table != NULL)
215 cal_shell_content_save_table_state (
216 E_SHELL_CONTENT (cal_shell_content),
217 E_TABLE (priv->memo_table));
218 }
219
220 static void
221 cal_shell_content_set_property (GObject *object,
222 guint property_id,
223 const GValue *value,
224 GParamSpec *pspec)
225 {
226 switch (property_id) {
227 }
228
229 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
230 }
231
232 static void
233 cal_shell_content_get_property (GObject *object,
234 guint property_id,
235 GValue *value,
236 GParamSpec *pspec)
237 {
238 switch (property_id) {
239 case PROP_CALENDAR:
240 g_value_set_object (
241 value, e_cal_shell_content_get_calendar (
242 E_CAL_SHELL_CONTENT (object)));
243 return;
244
245 case PROP_MEMO_TABLE:
246 g_value_set_object (
247 value, e_cal_shell_content_get_memo_table (
248 E_CAL_SHELL_CONTENT (object)));
249 return;
250
251 case PROP_TASK_TABLE:
252 g_value_set_object (
253 value, e_cal_shell_content_get_task_table (
254 E_CAL_SHELL_CONTENT (object)));
255 return;
256 }
257
258 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
259 }
260
261 static void
262 cal_shell_content_dispose (GObject *object)
263 {
264 ECalShellContentPrivate *priv;
265
266 priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
267
268 if (priv->hpaned != NULL) {
269 g_object_unref (priv->hpaned);
270 priv->hpaned = NULL;
271 }
272
273 if (priv->notebook != NULL) {
274 g_object_unref (priv->notebook);
275 priv->notebook = NULL;
276 }
277
278 if (priv->vpaned != NULL) {
279 g_object_unref (priv->vpaned);
280 priv->vpaned = NULL;
281 }
282
283 if (priv->calendar != NULL) {
284 g_object_unref (priv->calendar);
285 priv->calendar = NULL;
286 }
287
288 if (priv->task_table != NULL) {
289 g_object_unref (priv->task_table);
290 priv->task_table = NULL;
291 }
292
293 if (priv->memo_table != NULL) {
294 g_object_unref (priv->memo_table);
295 priv->memo_table = NULL;
296 }
297
298 if (priv->view_instance != NULL) {
299 g_object_unref (priv->view_instance);
300 priv->view_instance = NULL;
301 }
302
303 /* Chain up to parent's dispose() method. */
304 G_OBJECT_CLASS (e_cal_shell_content_parent_class)->dispose (object);
305 }
306
307 static time_t
308 gc_get_default_time (ECalModel *model,
309 gpointer user_data)
310 {
311 GnomeCalendar *gcal = user_data;
312 time_t res = 0, end;
313
314 g_return_val_if_fail (model != NULL, 0);
315 g_return_val_if_fail (GNOME_IS_CALENDAR (user_data), 0);
316
317 gnome_calendar_get_current_time_range (gcal, &res, &end);
318
319 return res;
320 }
321
322 static void
323 cal_shell_content_constructed (GObject *object)
324 {
325 ECalShellContentPrivate *priv;
326 ECalendarView *calendar_view;
327 ECalModel *memo_model = NULL;
328 ECalModel *task_model = NULL;
329 EShell *shell;
330 EShellContent *shell_content;
331 EShellView *shell_view;
332 EShellWindow *shell_window;
333 EShellContent *foreign_content;
334 EShellView *foreign_view;
335 GnomeCalendar *calendar;
336 ESourceRegistry *registry;
337 GalViewInstance *view_instance;
338 GSettings *settings;
339 GtkWidget *container;
340 GtkWidget *widget;
341 gchar *markup;
342 gint ii;
343
344 priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
345
346 /* Chain up to parent's constructed() method. */
347 G_OBJECT_CLASS (e_cal_shell_content_parent_class)->constructed (object);
348
349 shell_content = E_SHELL_CONTENT (object);
350 shell_view = e_shell_content_get_shell_view (shell_content);
351 shell_window = e_shell_view_get_shell_window (shell_view);
352
353 shell = e_shell_window_get_shell (shell_window);
354
355 /* We borrow the memopad and taskpad models from the memo
356 * and task views, loading the views if necessary. */
357 if (!e_shell_get_express_mode (shell)) {
358 foreign_view = e_shell_window_get_shell_view (shell_window, "memos");
359 foreign_content = e_shell_view_get_shell_content (foreign_view);
360 g_object_get (foreign_content, "model", &memo_model, NULL);
361
362 foreign_view = e_shell_window_get_shell_view (shell_window, "tasks");
363 foreign_content = e_shell_view_get_shell_content (foreign_view);
364 g_object_get (foreign_content, "model", &task_model, NULL);
365 }
366
367 /* Build content widgets. */
368
369 container = GTK_WIDGET (object);
370
371 if (!e_shell_get_express_mode (shell)) {
372 widget = e_paned_new (GTK_ORIENTATION_HORIZONTAL);
373 gtk_container_add (GTK_CONTAINER (container), widget);
374 priv->hpaned = g_object_ref (widget);
375 gtk_widget_show (widget);
376
377 container = priv->hpaned;
378 }
379
380 widget = gtk_notebook_new ();
381 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
382 gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
383 if (!e_shell_get_express_mode (shell))
384 gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
385 else
386 gtk_container_add (GTK_CONTAINER (container), widget);
387 priv->notebook = g_object_ref (widget);
388 gtk_widget_show (widget);
389
390 if (!e_shell_get_express_mode (shell)) {
391 /* FIXME Need to deal with saving and restoring the position.
392 * Month view has its own position. */
393 widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
394 e_paned_set_fixed_resize (E_PANED (widget), FALSE);
395 gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, TRUE);
396 priv->vpaned = g_object_ref (widget);
397 gtk_widget_show (widget);
398 }
399
400 container = priv->notebook;
401
402 /* Add views in the order defined by GnomeCalendarViewType, such
403 * that the notebook page number corresponds to the view type. */
404
405 registry = e_shell_get_registry (shell);
406 priv->calendar = gnome_calendar_new (registry);
407 calendar = GNOME_CALENDAR (priv->calendar);
408
409 for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) {
410 calendar_view = gnome_calendar_get_calendar_view (calendar, ii);
411
412 gtk_notebook_append_page (
413 GTK_NOTEBOOK (container),
414 GTK_WIDGET (calendar_view), NULL);
415 gtk_widget_show (GTK_WIDGET (calendar_view));
416 }
417
418 g_object_bind_property (
419 priv->calendar, "view",
420 priv->notebook, "page",
421 G_BINDING_SYNC_CREATE);
422
423 container = priv->vpaned;
424
425 if (!e_shell_get_express_mode (shell)) {
426 widget = gtk_vbox_new (FALSE, 0);
427 gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, TRUE);
428 gtk_widget_show (widget);
429
430 container = widget;
431
432 widget = gtk_hseparator_new ();
433 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
434 gtk_widget_show (widget);
435
436 widget = gtk_label_new (NULL);
437 markup = g_strdup_printf ("<b>%s</b>", _("Tasks"));
438 gtk_label_set_markup (GTK_LABEL (widget), markup);
439 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
440 gtk_widget_show (widget);
441 g_free (markup);
442
443 widget = gtk_scrolled_window_new (NULL, NULL);
444 gtk_scrolled_window_set_policy (
445 GTK_SCROLLED_WINDOW (widget),
446 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
447 gtk_scrolled_window_set_shadow_type (
448 GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
449 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
450 gtk_widget_show (widget);
451
452 container = widget;
453
454 widget = e_task_table_new (shell_view, task_model);
455 gtk_container_add (GTK_CONTAINER (container), widget);
456 priv->task_table = g_object_ref (widget);
457 gtk_widget_show (widget);
458
459 cal_shell_content_load_table_state (
460 shell_content, E_TABLE (widget));
461
462 g_signal_connect_swapped (
463 widget, "open-component",
464 G_CALLBACK (e_cal_shell_view_taskpad_open_task),
465 shell_view);
466
467 container = priv->vpaned;
468
469 widget = gtk_vbox_new (FALSE, 0);
470 gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, TRUE);
471 gtk_widget_show (widget);
472
473 container = widget;
474
475 widget = gtk_label_new (NULL);
476 markup = g_strdup_printf ("<b>%s</b>", _("Memos"));
477 gtk_label_set_markup (GTK_LABEL (widget), markup);
478 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
479 gtk_widget_show (widget);
480 g_free (markup);
481
482 widget = gtk_scrolled_window_new (NULL, NULL);
483 gtk_scrolled_window_set_policy (
484 GTK_SCROLLED_WINDOW (widget),
485 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
486 gtk_scrolled_window_set_shadow_type (
487 GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
488 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
489 gtk_widget_show (widget);
490
491 container = widget;
492
493 widget = e_memo_table_new (shell_view, memo_model);
494 gtk_container_add (GTK_CONTAINER (container), widget);
495 priv->memo_table = g_object_ref (widget);
496 gtk_widget_show (widget);
497
498 cal_shell_content_load_table_state (
499 shell_content, E_TABLE (widget));
500
501 e_cal_model_set_default_time_func (
502 memo_model, gc_get_default_time, calendar);
503
504 g_signal_connect_swapped (
505 widget, "open-component",
506 G_CALLBACK (e_cal_shell_view_memopad_open_memo),
507 shell_view);
508 }
509
510 /* Load the view instance. */
511
512 view_instance = e_shell_view_new_view_instance (shell_view, NULL);
513 g_signal_connect_swapped (
514 view_instance, "display-view",
515 G_CALLBACK (cal_shell_content_display_view_cb),
516 object);
517 /* XXX Actually, don't load the view instance just yet.
518 * The GtkWidget::map() callback below explains why. */
519 priv->view_instance = view_instance;
520
521 if (!e_shell_get_express_mode (shell)) {
522 g_signal_connect_swapped (
523 shell_view, "notify::view-id",
524 G_CALLBACK (cal_shell_content_notify_view_id_cb),
525 object);
526
527 settings = g_settings_new ("org.gnome.evolution.calendar");
528
529 g_settings_bind (
530 settings, "tag-vpane-position",
531 priv->vpaned, "proportion",
532 G_SETTINGS_BIND_DEFAULT);
533
534 g_object_unref (settings);
535 }
536
537 if (memo_model)
538 g_object_unref (memo_model);
539 if (task_model)
540 g_object_unref (task_model);
541 }
542
543 static void
544 cal_shell_content_map (GtkWidget *widget)
545 {
546 ECalShellContentPrivate *priv;
547
548 /* XXX Delay loading the GalViewInstance until after ECalShellView
549 * has a chance to install the sidebar's date navigator into
550 * GnomeCalendar, since loading the GalViewInstance triggers a
551 * callback in GnomeCalendar that requires the date navigator.
552 * Ordinarily we would do this at the end of constructed(), but
553 * that's too soon in this case. (This feels kind of kludgy.) */
554 priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (widget);
555 gal_view_instance_load (priv->view_instance);
556
557 /* Chain up to parent's map() method. */
558 GTK_WIDGET_CLASS (e_cal_shell_content_parent_class)->map (widget);
559 }
560
561 /* Helper for cal_shell_content_check_state() */
562 static icalproperty *
563 cal_shell_content_get_attendee_prop (icalcomponent *icalcomp,
564 const gchar *address)
565 {
566 icalproperty *prop;
567
568 if (address == NULL || *address == '\0')
569 return NULL;
570
571 prop = icalcomponent_get_first_property (
572 icalcomp, ICAL_ATTENDEE_PROPERTY);
573
574 while (prop != NULL) {
575 const gchar *attendee;
576
577 attendee = icalproperty_get_attendee (prop);
578
579 if (g_str_equal (itip_strip_mailto (attendee), address))
580 return prop;
581
582 prop = icalcomponent_get_next_property (
583 icalcomp, ICAL_ATTENDEE_PROPERTY);
584 }
585
586 return NULL;
587 }
588
589 /* Helper for cal_shell_content_check_state() */
590 static gboolean
591 cal_shell_content_icalcomp_is_delegated (icalcomponent *icalcomp,
592 const gchar *user_email)
593 {
594 icalproperty *prop;
595 icalparameter *param;
596 const gchar *delto = NULL;
597 gboolean is_delegated = FALSE;
598
599 prop = cal_shell_content_get_attendee_prop (icalcomp, user_email);
600
601 if (prop != NULL) {
602 param = icalproperty_get_first_parameter (
603 prop, ICAL_DELEGATEDTO_PARAMETER);
604 if (param != NULL) {
605 delto = icalparameter_get_delegatedto (param);
606 delto = itip_strip_mailto (delto);
607 }
608 } else
609 return FALSE;
610
611 prop = cal_shell_content_get_attendee_prop (icalcomp, delto);
612
613 if (prop != NULL) {
614 const gchar *delfrom = NULL;
615 icalparameter_partstat status = ICAL_PARTSTAT_NONE;
616
617 param = icalproperty_get_first_parameter (
618 prop, ICAL_DELEGATEDFROM_PARAMETER);
619 if (param != NULL) {
620 delfrom = icalparameter_get_delegatedfrom (param);
621 delfrom = itip_strip_mailto (delfrom);
622 }
623 param = icalproperty_get_first_parameter (
624 prop, ICAL_PARTSTAT_PARAMETER);
625 if (param != NULL)
626 status = icalparameter_get_partstat (param);
627 is_delegated =
628 (status != ICAL_PARTSTAT_DECLINED) &&
629 (g_strcmp0 (delfrom, user_email) == 0);
630 }
631
632 return is_delegated;
633 }
634
635 static guint32
636 cal_shell_content_check_state (EShellContent *shell_content)
637 {
638 EShell *shell;
639 EShellView *shell_view;
640 EShellBackend *shell_backend;
641 ESourceRegistry *registry;
642 ECalShellContent *cal_shell_content;
643 GnomeCalendar *calendar;
644 ECalendarView *calendar_view;
645 GnomeCalendarViewType view_type;
646 gboolean selection_is_editable = FALSE;
647 gboolean selection_is_instance = FALSE;
648 gboolean selection_is_meeting = FALSE;
649 gboolean selection_is_organizer = FALSE;
650 gboolean selection_is_recurring = FALSE;
651 gboolean selection_can_delegate = FALSE;
652 guint32 state = 0;
653 GList *selected;
654 GList *link;
655 guint n_selected;
656
657 cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
658
659 shell_view = e_shell_content_get_shell_view (shell_content);
660 shell_backend = e_shell_view_get_shell_backend (shell_view);
661 shell = e_shell_backend_get_shell (shell_backend);
662 registry = e_shell_get_registry (shell);
663
664 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
665 view_type = gnome_calendar_get_view (calendar);
666 calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
667
668 selected = e_calendar_view_get_selected_events (calendar_view);
669 n_selected = g_list_length (selected);
670
671 /* If we have a selection, assume it's
672 * editable until we learn otherwise. */
673 if (n_selected > 0)
674 selection_is_editable = TRUE;
675
676 for (link = selected; link != NULL; link = g_list_next (link)) {
677 ECalendarViewEvent *event = link->data;
678 ECalClient *client;
679 ECalComponent *comp;
680 gchar *user_email;
681 icalcomponent *icalcomp;
682 const gchar *capability;
683 gboolean cap_delegate_supported;
684 gboolean cap_delegate_to_many;
685 gboolean icalcomp_is_delegated;
686 gboolean read_only;
687
688 if (!is_comp_data_valid (event))
689 continue;
690
691 client = event->comp_data->client;
692 icalcomp = event->comp_data->icalcomp;
693
694 read_only = e_client_is_readonly (E_CLIENT (client));
695 selection_is_editable &= !read_only;
696
697 selection_is_instance |=
698 e_cal_util_component_is_instance (icalcomp);
699
700 selection_is_meeting =
701 (n_selected == 1) &&
702 e_cal_util_component_has_attendee (icalcomp);
703
704 selection_is_recurring |=
705 e_cal_util_component_is_instance (icalcomp) ||
706 e_cal_util_component_has_recurrences (icalcomp);
707
708 /* XXX The rest of this is rather expensive and
709 * only applies if a single event is selected,
710 * so continue with the loop iteration if the
711 * rest of this is not applicable. */
712 if (n_selected > 1)
713 continue;
714
715 /* XXX This probably belongs in comp-util.c. */
716
717 comp = e_cal_component_new ();
718 e_cal_component_set_icalcomponent (
719 comp, icalcomponent_new_clone (icalcomp));
720 user_email = itip_get_comp_attendee (
721 registry, comp, client);
722
723 selection_is_organizer =
724 e_cal_util_component_has_organizer (icalcomp) &&
725 itip_organizer_is_user (registry, comp, client);
726
727 capability = CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED;
728 cap_delegate_supported =
729 e_client_check_capability (
730 E_CLIENT (client), capability);
731
732 capability = CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY;
733 cap_delegate_to_many =
734 e_client_check_capability (
735 E_CLIENT (client), capability);
736
737 icalcomp_is_delegated =
738 (user_email != NULL) &&
739 cal_shell_content_icalcomp_is_delegated (
740 icalcomp, user_email);
741
742 selection_can_delegate =
743 cap_delegate_supported &&
744 (cap_delegate_to_many ||
745 (!selection_is_organizer &&
746 !icalcomp_is_delegated));
747
748 g_free (user_email);
749 g_object_unref (comp);
750 }
751
752 g_list_free (selected);
753
754 if (n_selected == 1)
755 state |= E_CAL_SHELL_CONTENT_SELECTION_SINGLE;
756 if (n_selected > 1)
757 state |= E_CAL_SHELL_CONTENT_SELECTION_MULTIPLE;
758 if (selection_is_editable)
759 state |= E_CAL_SHELL_CONTENT_SELECTION_IS_EDITABLE;
760 if (selection_is_instance)
761 state |= E_CAL_SHELL_CONTENT_SELECTION_IS_INSTANCE;
762 if (selection_is_meeting)
763 state |= E_CAL_SHELL_CONTENT_SELECTION_IS_MEETING;
764 if (selection_is_organizer)
765 state |= E_CAL_SHELL_CONTENT_SELECTION_IS_ORGANIZER;
766 if (selection_is_recurring)
767 state |= E_CAL_SHELL_CONTENT_SELECTION_IS_RECURRING;
768 if (selection_can_delegate)
769 state |= E_CAL_SHELL_CONTENT_SELECTION_CAN_DELEGATE;
770
771 return state;
772 }
773
774 static void
775 cal_shell_content_focus_search_results (EShellContent *shell_content)
776 {
777 ECalShellContent *cal_shell_content;
778 GnomeCalendar *calendar;
779 GnomeCalendarViewType view_type;
780 ECalendarView *calendar_view;
781
782 cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
783 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
784 view_type = gnome_calendar_get_view (calendar);
785 calendar_view = gnome_calendar_get_calendar_view (calendar, view_type);
786
787 gtk_widget_grab_focus (GTK_WIDGET (calendar_view));
788 }
789
790 static void
791 e_cal_shell_content_class_init (ECalShellContentClass *class)
792 {
793 GObjectClass *object_class;
794 GtkWidgetClass *widget_class;
795 EShellContentClass *shell_content_class;
796
797 g_type_class_add_private (class, sizeof (ECalShellContentPrivate));
798
799 object_class = G_OBJECT_CLASS (class);
800 object_class->set_property = cal_shell_content_set_property;
801 object_class->get_property = cal_shell_content_get_property;
802 object_class->dispose = cal_shell_content_dispose;
803 object_class->constructed = cal_shell_content_constructed;
804
805 widget_class = GTK_WIDGET_CLASS (class);
806 widget_class->map = cal_shell_content_map;
807
808 shell_content_class = E_SHELL_CONTENT_CLASS (class);
809 shell_content_class->check_state = cal_shell_content_check_state;
810 shell_content_class->focus_search_results = cal_shell_content_focus_search_results;
811
812 g_object_class_install_property (
813 object_class,
814 PROP_CALENDAR,
815 g_param_spec_object (
816 "calendar",
817 NULL,
818 NULL,
819 GNOME_TYPE_CALENDAR,
820 G_PARAM_READABLE));
821
822 g_object_class_install_property (
823 object_class,
824 PROP_MEMO_TABLE,
825 g_param_spec_object (
826 "memo-table",
827 NULL,
828 NULL,
829 E_TYPE_MEMO_TABLE,
830 G_PARAM_READABLE));
831
832 g_object_class_install_property (
833 object_class,
834 PROP_TASK_TABLE,
835 g_param_spec_object (
836 "task-table",
837 NULL,
838 NULL,
839 E_TYPE_TASK_TABLE,
840 G_PARAM_READABLE));
841 }
842
843 static void
844 e_cal_shell_content_class_finalize (ECalShellContentClass *class)
845 {
846 }
847
848 static void
849 e_cal_shell_content_init (ECalShellContent *cal_shell_content)
850 {
851 cal_shell_content->priv =
852 E_CAL_SHELL_CONTENT_GET_PRIVATE (cal_shell_content);
853
854 /* Postpone widget construction until we have a shell view. */
855 }
856
857 void
858 e_cal_shell_content_type_register (GTypeModule *type_module)
859 {
860 /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration
861 * function, so we have to wrap it with a public function in
862 * order to register types from a separate compilation unit. */
863 e_cal_shell_content_register_type (type_module);
864 }
865
866 GtkWidget *
867 e_cal_shell_content_new (EShellView *shell_view)
868 {
869 g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
870
871 return g_object_new (
872 E_TYPE_CAL_SHELL_CONTENT,
873 "shell-view", shell_view, NULL);
874 }
875
876 ECalModel *
877 e_cal_shell_content_get_model (ECalShellContent *cal_shell_content)
878 {
879 GnomeCalendar *calendar;
880
881 g_return_val_if_fail (
882 E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
883
884 calendar = e_cal_shell_content_get_calendar (cal_shell_content);
885
886 return gnome_calendar_get_model (calendar);
887 }
888
889 GnomeCalendar *
890 e_cal_shell_content_get_calendar (ECalShellContent *cal_shell_content)
891 {
892 g_return_val_if_fail (
893 E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
894
895 return GNOME_CALENDAR (cal_shell_content->priv->calendar);
896 }
897
898 EMemoTable *
899 e_cal_shell_content_get_memo_table (ECalShellContent *cal_shell_content)
900 {
901 g_return_val_if_fail (
902 E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
903
904 return E_MEMO_TABLE (cal_shell_content->priv->memo_table);
905 }
906
907 ETaskTable *
908 e_cal_shell_content_get_task_table (ECalShellContent *cal_shell_content)
909 {
910 g_return_val_if_fail (
911 E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
912
913 return E_TASK_TABLE (cal_shell_content->priv->task_table);
914 }
915
916 EShellSearchbar *
917 e_cal_shell_content_get_searchbar (ECalShellContent *cal_shell_content)
918 {
919 EShellView *shell_view;
920 EShellContent *shell_content;
921 GtkWidget *widget;
922
923 g_return_val_if_fail (
924 E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
925
926 shell_content = E_SHELL_CONTENT (cal_shell_content);
927 shell_view = e_shell_content_get_shell_view (shell_content);
928 widget = e_shell_view_get_searchbar (shell_view);
929
930 return E_SHELL_SEARCHBAR (widget);
931 }
932
933 GalViewInstance *
934 e_cal_shell_content_get_view_instance (ECalShellContent *cal_shell_content)
935 {
936 g_return_val_if_fail (
937 E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
938
939 return cal_shell_content->priv->view_instance;
940 }