Bug 793125 - Crash due to popup menus left attached too long
[evolution.git] / src / calendar / gui / e-comp-editor-event.c
blob40546a90aaecbf602c7c85c35007a19f9dd209c3
1 /*
2 * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "evolution-config.h"
20 #include <glib/gi18n-lib.h>
21 #include <gtk/gtk.h>
23 #include <e-util/e-util.h>
25 #include "calendar-config.h"
26 #include "comp-util.h"
27 #include "e-comp-editor.h"
28 #include "e-comp-editor-page.h"
29 #include "e-comp-editor-page-attachments.h"
30 #include "e-comp-editor-page-general.h"
31 #include "e-comp-editor-page-recurrence.h"
32 #include "e-comp-editor-page-reminders.h"
33 #include "e-comp-editor-page-schedule.h"
34 #include "e-comp-editor-property-parts.h"
35 #include "e-timezone-entry.h"
37 #include "e-comp-editor-event.h"
39 struct _ECompEditorEventPrivate {
40 ECompEditorPage *page_general;
41 ECompEditorPropertyPart *dtstart;
42 ECompEditorPropertyPart *dtend;
43 ECompEditorPropertyPart *categories;
44 ECompEditorPropertyPart *timezone;
45 ECompEditorPropertyPart *transparency;
46 GtkWidget *all_day_check;
48 gpointer in_the_past_alert;
49 gpointer insensitive_info_alert;
52 G_DEFINE_TYPE (ECompEditorEvent, e_comp_editor_event, E_TYPE_COMP_EDITOR)
54 static void
55 ece_event_action_classification_cb (GtkRadioAction *action,
56 GtkRadioAction *current,
57 ECompEditorEvent *event_editor)
59 g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
61 e_comp_editor_set_changed (E_COMP_EDITOR (event_editor), TRUE);
64 static void
65 ece_event_update_times (ECompEditorEvent *event_editor,
66 EDateEdit *date_edit,
67 gboolean change_end_datetime)
69 GtkWidget *widget;
70 guint flags;
72 g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
73 g_return_if_fail (E_IS_DATE_EDIT (date_edit));
75 widget = e_date_edit_get_entry (date_edit);
76 if (widget && gtk_widget_has_focus (widget))
77 return;
79 if (!e_comp_editor_get_updating (E_COMP_EDITOR (event_editor))) {
80 e_comp_editor_ensure_start_before_end (E_COMP_EDITOR (event_editor),
81 event_editor->priv->dtstart,
82 event_editor->priv->dtend,
83 change_end_datetime);
86 flags = e_comp_editor_get_flags (E_COMP_EDITOR (event_editor));
88 if ((flags & E_COMP_EDITOR_FLAG_IS_NEW) != 0) {
89 struct icaltimetype start_tt;
91 start_tt = e_comp_editor_property_part_datetime_get_value (
92 E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtstart));
94 if (cal_comp_util_compare_time_with_today (start_tt) < 0) {
95 if (!event_editor->priv->in_the_past_alert) {
96 EAlert *alert;
98 alert = e_comp_editor_add_warning (E_COMP_EDITOR (event_editor),
99 _("Event’s time is in the past"), NULL);
101 event_editor->priv->in_the_past_alert = alert;
103 if (alert)
104 g_object_add_weak_pointer (G_OBJECT (alert), &event_editor->priv->in_the_past_alert);
106 g_clear_object (&alert);
108 } else if (event_editor->priv->in_the_past_alert) {
109 e_alert_response (event_editor->priv->in_the_past_alert, GTK_RESPONSE_OK);
114 static void
115 ece_event_dtstart_changed_cb (EDateEdit *date_edit,
116 ECompEditorEvent *event_editor)
118 g_return_if_fail (E_IS_DATE_EDIT (date_edit));
119 g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
121 ece_event_update_times (event_editor, date_edit, TRUE);
124 static void
125 ece_event_dtend_changed_cb (EDateEdit *date_edit,
126 ECompEditorEvent *event_editor)
128 g_return_if_fail (E_IS_DATE_EDIT (date_edit));
129 g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
131 ece_event_update_times (event_editor, date_edit, FALSE);
134 static void
135 ece_event_all_day_toggled_cb (ECompEditorEvent *event_editor)
137 GtkWidget *edit_widget;
139 g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
141 edit_widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->dtstart);
143 ece_event_update_times (event_editor, E_DATE_EDIT (edit_widget), TRUE);
145 e_comp_editor_ensure_changed (E_COMP_EDITOR (event_editor));
148 static void
149 ece_event_sensitize_widgets (ECompEditor *comp_editor,
150 gboolean force_insensitive)
152 ECompEditorEvent *event_editor;
153 gboolean is_organizer;
154 GtkAction *action;
155 guint32 flags;
157 g_return_if_fail (E_IS_COMP_EDITOR_EVENT (comp_editor));
159 E_COMP_EDITOR_CLASS (e_comp_editor_event_parent_class)->sensitize_widgets (comp_editor, force_insensitive);
161 flags = e_comp_editor_get_flags (comp_editor);
162 is_organizer = (flags & (E_COMP_EDITOR_FLAG_IS_NEW | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER)) != 0;
163 event_editor = E_COMP_EDITOR_EVENT (comp_editor);
165 gtk_widget_set_sensitive (event_editor->priv->all_day_check, !force_insensitive && is_organizer);
167 #define sensitize_part(x) G_STMT_START { \
168 GtkWidget *widget; \
170 widget = e_comp_editor_property_part_get_label_widget (x); \
171 if (widget) \
172 gtk_widget_set_sensitive (widget, !force_insensitive && is_organizer); \
174 widget = e_comp_editor_property_part_get_edit_widget (x); \
175 if (widget) \
176 gtk_widget_set_sensitive (widget, !force_insensitive && is_organizer); \
177 } G_STMT_END
179 sensitize_part (event_editor->priv->dtstart);
180 sensitize_part (event_editor->priv->dtend);
181 sensitize_part (event_editor->priv->timezone);
183 #undef sensitize_part
185 action = e_comp_editor_get_action (comp_editor, "all-day-event");
186 gtk_action_set_sensitive (action, !force_insensitive && is_organizer);
188 action = e_comp_editor_get_action (comp_editor, "classification-menu");
189 gtk_action_set_sensitive (action, !force_insensitive && is_organizer);
191 if (event_editor->priv->insensitive_info_alert)
192 e_alert_response (event_editor->priv->insensitive_info_alert, GTK_RESPONSE_OK);
194 if (force_insensitive || !is_organizer) {
195 ECalClient *client;
196 const gchar *message = NULL;
198 client = e_comp_editor_get_target_client (comp_editor);
199 if (!client)
200 message = _("Event cannot be edited, because the selected calendar could not be opened");
201 else if (e_client_is_readonly (E_CLIENT (client)))
202 message = _("Event cannot be edited, because the selected calendar is read only");
203 else if (!is_organizer)
204 message = _("Event cannot be fully edited, because you are not the organizer");
206 if (message) {
207 EAlert *alert;
209 alert = e_comp_editor_add_information (comp_editor, message, NULL);
211 event_editor->priv->insensitive_info_alert = alert;
213 if (alert)
214 g_object_add_weak_pointer (G_OBJECT (alert), &event_editor->priv->insensitive_info_alert);
216 g_clear_object (&alert);
221 static icaltimezone *
222 ece_event_get_timezone_from_property (ECompEditor *comp_editor,
223 icalproperty *property)
225 ECalClient *client;
226 icalparameter *param;
227 icaltimezone *zone = NULL;
228 const gchar *tzid;
230 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL);
232 if (!property)
233 return NULL;
235 param = icalproperty_get_first_parameter (property, ICAL_TZID_PARAMETER);
236 if (!param)
237 return NULL;
239 tzid = icalparameter_get_tzid (param);
240 if (!tzid || !*tzid)
241 return NULL;
243 if (g_ascii_strcasecmp (tzid, "UTC") == 0)
244 return icaltimezone_get_utc_timezone ();
246 client = e_comp_editor_get_source_client (comp_editor);
247 /* It should be already fetched for the UI, thus this should be non-blocking. */
248 if (client && e_cal_client_get_timezone_sync (client, tzid, &zone, NULL, NULL) && zone)
249 return zone;
251 zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
252 if (!zone)
253 zone = icaltimezone_get_builtin_timezone (tzid);
255 return zone;
258 static void
259 ece_event_update_timezone (ECompEditorEvent *event_editor,
260 struct icaltimetype *out_dtstart,
261 struct icaltimetype *out_dtend)
263 ECompEditor *comp_editor;
264 struct icaltimetype dtstart, dtend;
265 icalcomponent *component;
266 icaltimezone *zone = NULL;
268 g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
270 comp_editor = E_COMP_EDITOR (event_editor);
272 dtstart = icaltime_null_time ();
273 dtend = icaltime_null_time ();
275 component = e_comp_editor_get_component (comp_editor);
276 if (!component) {
277 if (out_dtstart)
278 *out_dtstart = dtstart;
280 if (out_dtend)
281 *out_dtend = dtend;
283 return;
286 if (icalcomponent_get_first_property (component, ICAL_DTSTART_PROPERTY)) {
287 dtstart = icalcomponent_get_dtstart (component);
288 if (icaltime_is_valid_time (dtstart)) {
289 if (icaltime_is_utc (dtstart))
290 zone = icaltimezone_get_utc_timezone ();
291 else
292 zone = ece_event_get_timezone_from_property (comp_editor,
293 icalcomponent_get_first_property (component, ICAL_DTSTART_PROPERTY));
297 if (icalcomponent_get_first_property (component, ICAL_DTEND_PROPERTY)) {
298 dtend = icalcomponent_get_dtend (component);
299 if (!zone && icaltime_is_valid_time (dtend)) {
300 if (icaltime_is_utc (dtend))
301 zone = icaltimezone_get_utc_timezone ();
302 else
303 zone = ece_event_get_timezone_from_property (comp_editor,
304 icalcomponent_get_first_property (component, ICAL_DTEND_PROPERTY));
308 if (!zone) {
309 struct icaltimetype itt;
311 itt = icalcomponent_get_due (component);
312 if (icaltime_is_valid_time (itt)) {
313 if (icaltime_is_utc (itt))
314 zone = icaltimezone_get_utc_timezone ();
315 else
316 zone = ece_event_get_timezone_from_property (comp_editor,
317 icalcomponent_get_first_property (component, ICAL_DUE_PROPERTY));
321 if (zone) {
322 GtkWidget *edit_widget;
324 edit_widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->timezone);
326 e_timezone_entry_set_timezone (E_TIMEZONE_ENTRY (edit_widget), zone);
328 if (zone != calendar_config_get_icaltimezone ()) {
329 /* Show timezone part */
330 GtkAction *action;
332 action = e_comp_editor_get_action (comp_editor, "view-timezone");
333 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
337 if (out_dtstart)
338 *out_dtstart = dtstart;
340 if (out_dtend)
341 *out_dtend = dtend;
344 static void
345 ece_event_fill_widgets (ECompEditor *comp_editor,
346 icalcomponent *component)
348 ECompEditorEvent *event_editor;
349 struct icaltimetype dtstart, dtend;
350 icalproperty *prop;
351 gboolean all_day_event = FALSE;
352 GtkAction *action;
353 guint32 flags;
355 g_return_if_fail (E_IS_COMP_EDITOR_EVENT (comp_editor));
356 g_return_if_fail (component != NULL);
358 E_COMP_EDITOR_CLASS (e_comp_editor_event_parent_class)->fill_widgets (comp_editor, component);
360 event_editor = E_COMP_EDITOR_EVENT (comp_editor);
362 flags = e_comp_editor_get_flags (comp_editor);
363 dtstart = icaltime_null_time ();
364 dtend = icaltime_null_time ();
366 ece_event_update_timezone (event_editor, &dtstart, &dtend);
368 if (icaltime_is_valid_time (dtstart) && !icaltime_is_null_time (dtstart) &&
369 (!icaltime_is_valid_time (dtend) || icaltime_is_null_time (dtend))) {
370 dtend = dtstart;
371 if (dtstart.is_date)
372 icaltime_adjust (&dtend, 1, 0, 0, 0);
375 if (icaltime_is_valid_time (dtend) && !icaltime_is_null_time (dtend)) {
376 if (dtstart.is_date && dtend.is_date) {
377 all_day_event = TRUE;
378 if (icaltime_compare_date_only (dtend, dtstart) > 0) {
379 icaltime_adjust (&dtend, -1, 0, 0, 0);
383 e_comp_editor_property_part_datetime_set_value (
384 E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtend), dtend);
387 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (event_editor->priv->all_day_check), all_day_event);
389 prop = icalcomponent_get_first_property (component, ICAL_CLASS_PROPERTY);
390 if (prop && icalproperty_get_class (prop) == ICAL_CLASS_PRIVATE)
391 action = e_comp_editor_get_action (comp_editor, "classify-private");
392 else if (prop && icalproperty_get_class (prop) == ICAL_CLASS_CONFIDENTIAL)
393 action = e_comp_editor_get_action (comp_editor, "classify-confidential");
394 else if (!(flags & E_COMP_EDITOR_FLAG_IS_NEW))
395 action = e_comp_editor_get_action (comp_editor, "classify-public");
396 else {
397 GSettings *settings;
399 settings = e_util_ref_settings ("org.gnome.evolution.calendar");
401 if (g_settings_get_boolean (settings, "classify-private")) {
402 action = e_comp_editor_get_action (comp_editor, "classify-private");
403 } else {
404 action = e_comp_editor_get_action (comp_editor, "classify-public");
407 g_object_unref (settings);
410 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
413 static gboolean
414 ece_event_fill_component (ECompEditor *comp_editor,
415 icalcomponent *component)
417 ECompEditorEvent *event_editor;
418 gboolean date_valid, time_valid;
419 icalproperty *dtstart_prop, *dtend_prop;
420 icalproperty *prop;
421 icalproperty_class class_value;
423 g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE);
424 g_return_val_if_fail (component != NULL, FALSE);
426 if (!E_COMP_EDITOR_CLASS (e_comp_editor_event_parent_class)->fill_component (comp_editor, component))
427 return FALSE;
429 event_editor = E_COMP_EDITOR_EVENT (comp_editor);
431 if (!e_comp_editor_property_part_datetime_check_validity (
432 E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtstart), &date_valid, &time_valid)) {
433 const gchar *error_message = NULL;
435 if (!date_valid)
436 error_message = g_strdup (_("Start date is not a valid date"));
437 else if (!time_valid)
438 error_message = g_strdup (_("Start time is not a valid time"));
440 e_comp_editor_set_validation_error (comp_editor, event_editor->priv->page_general,
441 e_comp_editor_property_part_get_edit_widget (event_editor->priv->dtstart),
442 error_message ? error_message : _("Unknown error"));
444 return FALSE;
447 if (!e_comp_editor_property_part_datetime_check_validity (
448 E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtend), &date_valid, &time_valid)) {
449 const gchar *error_message = NULL;
451 if (!date_valid)
452 error_message = g_strdup (_("End date is not a valid date"));
453 else if (!time_valid)
454 error_message = g_strdup (_("End time is not a valid time"));
456 e_comp_editor_set_validation_error (comp_editor, event_editor->priv->page_general,
457 e_comp_editor_property_part_get_edit_widget (event_editor->priv->dtend),
458 error_message ? error_message : _("Unknown error"));
460 return FALSE;
463 dtstart_prop = icalcomponent_get_first_property (component, ICAL_DTSTART_PROPERTY);
464 dtend_prop = icalcomponent_get_first_property (component, ICAL_DTEND_PROPERTY);
466 if (dtstart_prop && dtend_prop) {
467 struct icaltimetype dtstart, dtend;
468 gboolean set_dtstart = FALSE, set_dtend = FALSE;
470 dtstart = icalproperty_get_dtstart (dtstart_prop);
471 dtend = icalproperty_get_dtend (dtend_prop);
473 if (dtstart.is_date && dtend.is_date) {
474 ECalClient *client;
476 /* Add 1 day to DTEND, as it is not inclusive. */
477 icaltime_adjust (&dtend, 1, 0, 0, 0);
478 set_dtend = TRUE;
480 client = e_comp_editor_get_target_client (comp_editor);
481 if (client && e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_ALL_DAY_EVENT_AS_TIME)) {
482 ECompEditorEvent *event_editor = E_COMP_EDITOR_EVENT (comp_editor);
483 GtkWidget *timezone_entry;
485 dtstart.is_date = FALSE;
486 dtstart.hour = 0;
487 dtstart.minute = 0;
488 dtstart.second = 0;
490 dtend.is_date = FALSE;
491 dtend.hour = 0;
492 dtend.minute = 0;
493 dtend.second = 0;
495 timezone_entry = e_comp_editor_property_part_get_edit_widget (event_editor->priv->timezone);
497 dtstart.zone = e_timezone_entry_get_timezone (E_TIMEZONE_ENTRY (timezone_entry));
498 if (!dtstart.zone)
499 dtstart.zone = icaltimezone_get_utc_timezone ();
501 dtend.zone = dtstart.zone;
503 set_dtstart = TRUE;
504 set_dtend = TRUE;
508 if (set_dtstart) {
509 icalproperty_set_dtstart (dtstart_prop, dtstart);
510 cal_comp_util_update_tzid_parameter (dtstart_prop, dtstart);
513 if (set_dtend) {
514 icalproperty_set_dtend (dtend_prop, dtend);
515 cal_comp_util_update_tzid_parameter (dtend_prop, dtend);
519 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (
520 e_comp_editor_get_action (comp_editor, "classify-private"))))
521 class_value = ICAL_CLASS_PRIVATE;
522 else if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (
523 e_comp_editor_get_action (comp_editor, "classify-confidential"))))
524 class_value = ICAL_CLASS_CONFIDENTIAL;
525 else
526 class_value = ICAL_CLASS_PUBLIC;
528 prop = icalcomponent_get_first_property (component, ICAL_CLASS_PROPERTY);
529 if (prop) {
530 icalproperty_set_class (prop, class_value);
531 } else {
532 prop = icalproperty_new_class (class_value);
533 icalcomponent_add_property (component, prop);
536 return TRUE;
539 static void
540 ece_event_notify_source_client_cb (GObject *object,
541 GParamSpec *param,
542 gpointer user_data)
544 g_return_if_fail (E_IS_COMP_EDITOR_EVENT (object));
546 ece_event_update_timezone (E_COMP_EDITOR_EVENT (object), NULL, NULL);
549 static void
550 ece_event_setup_ui (ECompEditorEvent *event_editor)
552 const gchar *ui =
553 "<ui>"
554 " <menubar action='main-menu'>"
555 " <menu action='view-menu'>"
556 " <placeholder name='parts'>"
557 " <menuitem action='view-timezone'/>"
558 " <menuitem action='view-categories'/>"
559 " </placeholder>"
560 " </menu>"
561 " <menu action='options-menu'>"
562 " <placeholder name='toggles'>"
563 " <menuitem action='all-day-event'/>"
564 " <menuitem action='show-time-busy'/>"
565 " <menu action='classification-menu'>"
566 " <menuitem action='classify-public'/>"
567 " <menuitem action='classify-private'/>"
568 " <menuitem action='classify-confidential'/>"
569 " </menu>"
570 " </placeholder>"
571 " </menu>"
572 " </menubar>"
573 " <toolbar name='main-toolbar'>"
574 " <placeholder name='content'>\n"
575 " <toolitem action='all-day-event'/>\n"
576 " <toolitem action='show-time-busy'/>\n"
577 " </placeholder>"
578 " </toolbar>"
579 "</ui>";
581 const GtkToggleActionEntry view_actions[] = {
582 { "view-categories",
583 NULL,
584 N_("_Categories"),
585 NULL,
586 N_("Toggles whether to display categories"),
587 NULL,
588 FALSE },
590 { "view-timezone",
591 "stock_timezone",
592 N_("Time _Zone"),
593 NULL,
594 N_("Toggles whether the time zone is displayed"),
595 NULL,
596 FALSE },
598 { "all-day-event",
599 "stock_new-24h-appointment",
600 N_("All _Day Event"),
601 NULL,
602 N_("Toggles whether to have All Day Event"),
603 NULL,
604 FALSE },
606 { "show-time-busy",
607 "dialog-error",
608 N_("Show Time as _Busy"),
609 NULL,
610 N_("Toggles whether to show time as busy"),
611 NULL,
612 FALSE }
615 const GtkRadioActionEntry classification_radio_entries[] = {
617 { "classify-public",
618 NULL,
619 N_("Pu_blic"),
620 NULL,
621 N_("Classify as public"),
622 ICAL_CLASS_PUBLIC },
624 { "classify-private",
625 NULL,
626 N_("_Private"),
627 NULL,
628 N_("Classify as private"),
629 ICAL_CLASS_PRIVATE },
631 { "classify-confidential",
632 NULL,
633 N_("_Confidential"),
634 NULL,
635 N_("Classify as confidential"),
636 ICAL_CLASS_CONFIDENTIAL }
639 ECompEditor *comp_editor;
640 GSettings *settings;
641 GtkUIManager *ui_manager;
642 GtkAction *action;
643 GtkActionGroup *action_group;
644 GtkWidget *widget;
645 GError *error = NULL;
647 g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
649 comp_editor = E_COMP_EDITOR (event_editor);
650 settings = e_comp_editor_get_settings (comp_editor);
651 ui_manager = e_comp_editor_get_ui_manager (comp_editor);
652 action_group = e_comp_editor_get_action_group (comp_editor, "individual");
654 gtk_action_group_add_toggle_actions (action_group,
655 view_actions, G_N_ELEMENTS (view_actions), event_editor);
657 gtk_action_group_add_radio_actions (
658 action_group, classification_radio_entries,
659 G_N_ELEMENTS (classification_radio_entries),
660 ICAL_CLASS_PUBLIC,
661 G_CALLBACK (ece_event_action_classification_cb), event_editor);
663 gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
665 e_plugin_ui_register_manager (ui_manager, "org.gnome.evolution.event-editor", event_editor);
666 e_plugin_ui_enable_manager (ui_manager, "org.gnome.evolution.event-editor");
668 if (error) {
669 g_critical ("%s: %s", G_STRFUNC, error->message);
670 g_error_free (error);
673 action = e_comp_editor_get_action (comp_editor, "view-categories");
674 e_binding_bind_property (
675 event_editor->priv->categories, "visible",
676 action, "active",
677 G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
678 g_settings_bind (
679 settings, "editor-show-categories",
680 action, "active",
681 G_SETTINGS_BIND_DEFAULT);
683 action = e_comp_editor_get_action (comp_editor, "view-timezone");
684 e_binding_bind_property (
685 event_editor->priv->timezone, "visible",
686 action, "active",
687 G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
688 g_settings_bind (
689 settings, "editor-show-timezone",
690 action, "active",
691 G_SETTINGS_BIND_DEFAULT);
693 action = e_comp_editor_get_action (comp_editor, "all-day-event");
694 e_binding_bind_property (
695 event_editor->priv->all_day_check, "active",
696 action, "active",
697 G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
699 widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->transparency);
700 action = e_comp_editor_get_action (comp_editor, "show-time-busy");
701 e_binding_bind_property (
702 widget, "active",
703 action, "active",
704 G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
707 static void
708 e_comp_editor_event_constructed (GObject *object)
710 ECompEditor *comp_editor;
711 ECompEditorEvent *event_editor;
712 ECompEditorPage *page;
713 ECompEditorPropertyPart *part;
714 ECompEditorPropertyPart *summary;
715 EFocusTracker *focus_tracker;
716 GtkWidget *widget;
718 G_OBJECT_CLASS (e_comp_editor_event_parent_class)->constructed (object);
720 event_editor = E_COMP_EDITOR_EVENT (object);
721 comp_editor = E_COMP_EDITOR (event_editor);
722 focus_tracker = e_comp_editor_get_focus_tracker (comp_editor);
724 page = e_comp_editor_page_general_new (comp_editor,
725 _("_Calendar:"), E_SOURCE_EXTENSION_CALENDAR,
726 NULL, FALSE, 2);
727 event_editor->priv->page_general = page;
729 part = e_comp_editor_property_part_summary_new (focus_tracker);
730 e_comp_editor_page_add_property_part (page, part, 0, 2, 3, 1);
731 summary = part;
733 part = e_comp_editor_property_part_location_new (focus_tracker);
734 e_comp_editor_page_add_property_part (page, part, 0, 3, 3, 1);
736 part = e_comp_editor_property_part_dtstart_new (C_("ECompEditor", "_Start time:"), FALSE, FALSE);
737 e_comp_editor_page_add_property_part (page, part, 0, 4, 2, 1);
738 e_comp_editor_property_part_set_sensitize_handled (part, TRUE);
739 event_editor->priv->dtstart = part;
741 part = e_comp_editor_property_part_dtend_new (C_("ECompEditor", "_End time:"), FALSE, FALSE);
742 e_comp_editor_page_add_property_part (page, part, 0, 5, 2, 1);
743 e_comp_editor_property_part_set_sensitize_handled (part, TRUE);
744 event_editor->priv->dtend = part;
746 part = e_comp_editor_property_part_timezone_new ();
747 e_comp_editor_page_add_property_part (page, part, 0, 6, 3, 1);
748 e_comp_editor_property_part_set_sensitize_handled (part, TRUE);
749 event_editor->priv->timezone = part;
751 widget = gtk_check_button_new_with_mnemonic (C_("ECompEditor", "All da_y event"));
752 g_object_set (G_OBJECT (widget),
753 "hexpand", TRUE,
754 "halign", GTK_ALIGN_FILL,
755 "vexpand", FALSE,
756 "valign", GTK_ALIGN_START,
757 NULL);
758 gtk_grid_attach (GTK_GRID (page), widget, 2, 4, 1, 1);
759 gtk_widget_show (widget);
760 event_editor->priv->all_day_check = widget;
762 part = e_comp_editor_property_part_transparency_new ();
763 e_comp_editor_page_add_property_part (page, part, 2, 5, 1, 1);
764 event_editor->priv->transparency = part;
766 widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->transparency);
767 /* Transparency checkbox is not shown in the page, even it's packed there */
768 gtk_widget_hide (widget);
770 part = e_comp_editor_property_part_categories_new (focus_tracker);
771 e_comp_editor_page_add_property_part (page, part, 0, 7, 3, 1);
772 event_editor->priv->categories = part;
774 part = e_comp_editor_property_part_description_new (focus_tracker);
775 e_comp_editor_page_add_property_part (page, part, 0, 8, 3, 1);
777 widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->timezone);
778 e_comp_editor_property_part_datetime_attach_timezone_entry (
779 E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtstart),
780 E_TIMEZONE_ENTRY (widget));
781 e_comp_editor_property_part_datetime_attach_timezone_entry (
782 E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtend),
783 E_TIMEZONE_ENTRY (widget));
785 e_comp_editor_set_time_parts (comp_editor, event_editor->priv->dtstart, event_editor->priv->dtend);
787 widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->dtstart);
788 e_binding_bind_property (
789 event_editor->priv->all_day_check, "active",
790 widget, "show-time",
791 G_BINDING_INVERT_BOOLEAN | G_BINDING_BIDIRECTIONAL);
792 g_signal_connect (widget, "changed", G_CALLBACK (ece_event_dtstart_changed_cb), event_editor);
794 widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->dtend);
795 e_binding_bind_property (
796 event_editor->priv->all_day_check, "active",
797 widget, "show-time",
798 G_BINDING_INVERT_BOOLEAN | G_BINDING_BIDIRECTIONAL);
799 g_signal_connect (widget, "changed", G_CALLBACK (ece_event_dtend_changed_cb), event_editor);
801 e_signal_connect_notify_swapped (event_editor->priv->all_day_check, "notify::active",
802 G_CALLBACK (ece_event_all_day_toggled_cb), event_editor);
804 e_comp_editor_add_page (comp_editor, C_("ECompEditorPage", "General"), page);
806 page = e_comp_editor_page_reminders_new (comp_editor);
807 e_comp_editor_add_page (comp_editor, C_("ECompEditorPage", "Reminders"), page);
809 page = e_comp_editor_page_recurrence_new (comp_editor);
810 e_comp_editor_add_page (comp_editor, C_("ECompEditorPage", "Recurrence"), page);
812 page = e_comp_editor_page_attachments_new (comp_editor);
813 e_comp_editor_add_page (comp_editor, C_("ECompEditorPage", "Attachments"), page);
815 page = e_comp_editor_page_schedule_new (comp_editor,
816 e_comp_editor_page_general_get_meeting_store (
817 E_COMP_EDITOR_PAGE_GENERAL (event_editor->priv->page_general)));
818 e_binding_bind_property (
819 event_editor->priv->page_general, "show-attendees",
820 page, "visible",
821 G_BINDING_SYNC_CREATE);
823 e_comp_editor_add_page (comp_editor, C_("ECompEditorPage", "Schedule"), page);
825 ece_event_setup_ui (event_editor);
827 widget = e_comp_editor_property_part_get_edit_widget (summary);
828 e_binding_bind_property (widget, "text", comp_editor, "title-suffix", 0);
829 /* Do this as the last thing, because some widgets can call the function as well */
830 gtk_widget_grab_focus (widget);
832 g_signal_connect (comp_editor, "notify::source-client",
833 G_CALLBACK (ece_event_notify_source_client_cb), NULL);
836 static void
837 e_comp_editor_event_init (ECompEditorEvent *event_editor)
839 event_editor->priv = G_TYPE_INSTANCE_GET_PRIVATE (event_editor, E_TYPE_COMP_EDITOR_EVENT, ECompEditorEventPrivate);
842 static void
843 e_comp_editor_event_class_init (ECompEditorEventClass *klass)
845 GObjectClass *object_class;
846 ECompEditorClass *comp_editor_class;
848 g_type_class_add_private (klass, sizeof (ECompEditorEventPrivate));
850 object_class = G_OBJECT_CLASS (klass);
851 object_class->constructed = e_comp_editor_event_constructed;
853 comp_editor_class = E_COMP_EDITOR_CLASS (klass);
854 comp_editor_class->help_section = "calendar-usage-add-appointment";
855 comp_editor_class->title_format_with_attendees = _("Meeting — %s");
856 comp_editor_class->title_format_without_attendees = _("Appointment — %s");
857 comp_editor_class->icon_name = "appointment-new";
858 comp_editor_class->sensitize_widgets = ece_event_sensitize_widgets;
859 comp_editor_class->fill_widgets = ece_event_fill_widgets;
860 comp_editor_class->fill_component = ece_event_fill_component;