/*
* Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "evolution-config.h"
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include <e-util/e-util.h>
#include "calendar-config.h"
#include "comp-util.h"
#include "e-comp-editor.h"
#include "e-comp-editor-page.h"
#include "e-comp-editor-page-attachments.h"
#include "e-comp-editor-page-general.h"
#include "e-comp-editor-page-recurrence.h"
#include "e-comp-editor-page-reminders.h"
#include "e-comp-editor-page-schedule.h"
#include "e-comp-editor-property-parts.h"
#include "e-timezone-entry.h"
#include "e-comp-editor-event.h"
struct _ECompEditorEventPrivate {
ECompEditorPage *page_general;
ECompEditorPropertyPart *dtstart;
ECompEditorPropertyPart *dtend;
ECompEditorPropertyPart *categories;
ECompEditorPropertyPart *timezone;
ECompEditorPropertyPart *transparency;
ECompEditorPropertyPart *description;
GtkWidget *all_day_check;
gpointer in_the_past_alert;
gpointer insensitive_info_alert;
};
G_DEFINE_TYPE (ECompEditorEvent, e_comp_editor_event, E_TYPE_COMP_EDITOR)
static void
ece_event_action_classification_cb (GtkRadioAction *action,
GtkRadioAction *current,
ECompEditorEvent *event_editor)
{
g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
e_comp_editor_set_changed (E_COMP_EDITOR (event_editor), TRUE);
}
static void
ece_event_update_times (ECompEditorEvent *event_editor,
EDateEdit *date_edit,
gboolean change_end_datetime)
{
guint flags;
g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
g_return_if_fail (E_IS_DATE_EDIT (date_edit));
if (e_date_edit_has_focus (date_edit) ||
!e_date_edit_date_is_valid (date_edit) ||
!e_date_edit_time_is_valid (date_edit))
return;
if (!e_comp_editor_get_updating (E_COMP_EDITOR (event_editor))) {
e_comp_editor_ensure_start_before_end (E_COMP_EDITOR (event_editor),
event_editor->priv->dtstart,
event_editor->priv->dtend,
change_end_datetime);
}
flags = e_comp_editor_get_flags (E_COMP_EDITOR (event_editor));
if ((flags & E_COMP_EDITOR_FLAG_IS_NEW) != 0) {
struct icaltimetype start_tt;
start_tt = e_comp_editor_property_part_datetime_get_value (
E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtstart));
if (cal_comp_util_compare_time_with_today (start_tt) < 0) {
if (!event_editor->priv->in_the_past_alert) {
EAlert *alert;
alert = e_comp_editor_add_warning (E_COMP_EDITOR (event_editor),
_("Event’s time is in the past"), NULL);
event_editor->priv->in_the_past_alert = alert;
if (alert)
g_object_add_weak_pointer (G_OBJECT (alert), &event_editor->priv->in_the_past_alert);
g_clear_object (&alert);
}
} else if (event_editor->priv->in_the_past_alert) {
e_alert_response (event_editor->priv->in_the_past_alert, GTK_RESPONSE_OK);
}
}
}
static void
ece_event_dtstart_changed_cb (EDateEdit *date_edit,
ECompEditorEvent *event_editor)
{
g_return_if_fail (E_IS_DATE_EDIT (date_edit));
g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
ece_event_update_times (event_editor, date_edit, TRUE);
}
static void
ece_event_dtend_changed_cb (EDateEdit *date_edit,
ECompEditorEvent *event_editor)
{
g_return_if_fail (E_IS_DATE_EDIT (date_edit));
g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
ece_event_update_times (event_editor, date_edit, FALSE);
}
static void
ece_event_all_day_toggled_cb (ECompEditorEvent *event_editor)
{
GtkWidget *edit_widget;
g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
edit_widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->dtstart);
ece_event_update_times (event_editor, E_DATE_EDIT (edit_widget), TRUE);
e_comp_editor_ensure_changed (E_COMP_EDITOR (event_editor));
}
static void
ece_event_sensitize_widgets (ECompEditor *comp_editor,
gboolean force_insensitive)
{
ECompEditorEvent *event_editor;
gboolean is_organizer;
GtkAction *action;
GtkWidget *widget;
guint32 flags;
g_return_if_fail (E_IS_COMP_EDITOR_EVENT (comp_editor));
E_COMP_EDITOR_CLASS (e_comp_editor_event_parent_class)->sensitize_widgets (comp_editor, force_insensitive);
flags = e_comp_editor_get_flags (comp_editor);
is_organizer = (flags & (E_COMP_EDITOR_FLAG_IS_NEW | E_COMP_EDITOR_FLAG_ORGANIZER_IS_USER)) != 0;
event_editor = E_COMP_EDITOR_EVENT (comp_editor);
gtk_widget_set_sensitive (event_editor->priv->all_day_check, !force_insensitive && is_organizer);
#define sensitize_part(x) G_STMT_START { \
widget = e_comp_editor_property_part_get_label_widget (x); \
if (widget) \
gtk_widget_set_sensitive (widget, !force_insensitive && is_organizer); \
\
widget = e_comp_editor_property_part_get_edit_widget (x); \
if (widget) \
gtk_widget_set_sensitive (widget, !force_insensitive && is_organizer); \
} G_STMT_END
sensitize_part (event_editor->priv->dtstart);
sensitize_part (event_editor->priv->dtend);
sensitize_part (event_editor->priv->timezone);
#undef sensitize_part
/* Make the Description read-only, not completely insensitive,
thus it can be read and scrolled through and so on */
widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->description);
gtk_text_view_set_editable (GTK_TEXT_VIEW (gtk_bin_get_child (GTK_BIN (widget))), gtk_widget_get_sensitive (widget));
gtk_widget_set_sensitive (widget, TRUE);
action = e_comp_editor_get_action (comp_editor, "all-day-event");
gtk_action_set_sensitive (action, !force_insensitive && is_organizer);
action = e_comp_editor_get_action (comp_editor, "classification-menu");
gtk_action_set_sensitive (action, !force_insensitive && is_organizer);
if (event_editor->priv->insensitive_info_alert)
e_alert_response (event_editor->priv->insensitive_info_alert, GTK_RESPONSE_OK);
if (force_insensitive || !is_organizer) {
ECalClient *client;
const gchar *message = NULL;
client = e_comp_editor_get_target_client (comp_editor);
if (!client)
message = _("Event cannot be edited, because the selected calendar could not be opened");
else if (e_client_is_readonly (E_CLIENT (client)))
message = _("Event cannot be edited, because the selected calendar is read only");
else if (!is_organizer)
message = _("Event cannot be fully edited, because you are not the organizer");
if (message) {
EAlert *alert;
alert = e_comp_editor_add_information (comp_editor, message, NULL);
event_editor->priv->insensitive_info_alert = alert;
if (alert)
g_object_add_weak_pointer (G_OBJECT (alert), &event_editor->priv->insensitive_info_alert);
g_clear_object (&alert);
}
}
}
static icaltimezone *
ece_event_get_timezone_from_property (ECompEditor *comp_editor,
icalproperty *property)
{
ECalClient *client;
icalparameter *param;
icaltimezone *zone = NULL;
const gchar *tzid;
g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL);
if (!property)
return NULL;
param = icalproperty_get_first_parameter (property, ICAL_TZID_PARAMETER);
if (!param)
return NULL;
tzid = icalparameter_get_tzid (param);
if (!tzid || !*tzid)
return NULL;
if (g_ascii_strcasecmp (tzid, "UTC") == 0)
return icaltimezone_get_utc_timezone ();
client = e_comp_editor_get_source_client (comp_editor);
/* It should be already fetched for the UI, thus this should be non-blocking. */
if (client && e_cal_client_get_timezone_sync (client, tzid, &zone, NULL, NULL) && zone)
return zone;
zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
if (!zone)
zone = icaltimezone_get_builtin_timezone (tzid);
return zone;
}
static void
ece_event_update_timezone (ECompEditorEvent *event_editor,
struct icaltimetype *out_dtstart,
struct icaltimetype *out_dtend)
{
ECompEditor *comp_editor;
struct icaltimetype dtstart, dtend;
icalcomponent *component;
icaltimezone *zone = NULL;
g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
comp_editor = E_COMP_EDITOR (event_editor);
dtstart = icaltime_null_time ();
dtend = icaltime_null_time ();
component = e_comp_editor_get_component (comp_editor);
if (!component) {
if (out_dtstart)
*out_dtstart = dtstart;
if (out_dtend)
*out_dtend = dtend;
return;
}
if (icalcomponent_get_first_property (component, ICAL_DTSTART_PROPERTY)) {
dtstart = icalcomponent_get_dtstart (component);
if (icaltime_is_valid_time (dtstart)) {
if (icaltime_is_utc (dtstart))
zone = icaltimezone_get_utc_timezone ();
else
zone = ece_event_get_timezone_from_property (comp_editor,
icalcomponent_get_first_property (component, ICAL_DTSTART_PROPERTY));
}
}
if (icalcomponent_get_first_property (component, ICAL_DTEND_PROPERTY)) {
dtend = icalcomponent_get_dtend (component);
if (!zone && icaltime_is_valid_time (dtend)) {
if (icaltime_is_utc (dtend))
zone = icaltimezone_get_utc_timezone ();
else
zone = ece_event_get_timezone_from_property (comp_editor,
icalcomponent_get_first_property (component, ICAL_DTEND_PROPERTY));
}
}
if (!zone) {
struct icaltimetype itt;
itt = icalcomponent_get_due (component);
if (icaltime_is_valid_time (itt)) {
if (icaltime_is_utc (itt))
zone = icaltimezone_get_utc_timezone ();
else
zone = ece_event_get_timezone_from_property (comp_editor,
icalcomponent_get_first_property (component, ICAL_DUE_PROPERTY));
}
}
if (zone) {
GtkWidget *edit_widget;
edit_widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->timezone);
e_timezone_entry_set_timezone (E_TIMEZONE_ENTRY (edit_widget), zone);
if (zone != calendar_config_get_icaltimezone ()) {
/* Show timezone part */
GtkAction *action;
action = e_comp_editor_get_action (comp_editor, "view-timezone");
gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
}
}
if (out_dtstart)
*out_dtstart = dtstart;
if (out_dtend)
*out_dtend = dtend;
}
static void
ece_event_fill_widgets (ECompEditor *comp_editor,
icalcomponent *component)
{
ECompEditorEvent *event_editor;
struct icaltimetype dtstart, dtend;
icalproperty *prop;
gboolean all_day_event = FALSE;
GtkAction *action;
guint32 flags;
g_return_if_fail (E_IS_COMP_EDITOR_EVENT (comp_editor));
g_return_if_fail (component != NULL);
E_COMP_EDITOR_CLASS (e_comp_editor_event_parent_class)->fill_widgets (comp_editor, component);
event_editor = E_COMP_EDITOR_EVENT (comp_editor);
flags = e_comp_editor_get_flags (comp_editor);
dtstart = icaltime_null_time ();
dtend = icaltime_null_time ();
ece_event_update_timezone (event_editor, &dtstart, &dtend);
if (icaltime_is_valid_time (dtstart) && !icaltime_is_null_time (dtstart) &&
(!icaltime_is_valid_time (dtend) || icaltime_is_null_time (dtend))) {
dtend = dtstart;
if (dtstart.is_date)
icaltime_adjust (&dtend, 1, 0, 0, 0);
}
if (icaltime_is_valid_time (dtend) && !icaltime_is_null_time (dtend)) {
if (dtstart.is_date && dtend.is_date) {
all_day_event = TRUE;
if (icaltime_compare_date_only (dtend, dtstart) > 0) {
icaltime_adjust (&dtend, -1, 0, 0, 0);
}
}
e_comp_editor_property_part_datetime_set_value (
E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtend), dtend);
}
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (event_editor->priv->all_day_check), all_day_event);
prop = icalcomponent_get_first_property (component, ICAL_CLASS_PROPERTY);
if (prop && icalproperty_get_class (prop) == ICAL_CLASS_PRIVATE)
action = e_comp_editor_get_action (comp_editor, "classify-private");
else if (prop && icalproperty_get_class (prop) == ICAL_CLASS_CONFIDENTIAL)
action = e_comp_editor_get_action (comp_editor, "classify-confidential");
else if (!(flags & E_COMP_EDITOR_FLAG_IS_NEW))
action = e_comp_editor_get_action (comp_editor, "classify-public");
else {
GSettings *settings;
settings = e_util_ref_settings ("org.gnome.evolution.calendar");
if (g_settings_get_boolean (settings, "classify-private")) {
action = e_comp_editor_get_action (comp_editor, "classify-private");
} else {
action = e_comp_editor_get_action (comp_editor, "classify-public");
}
g_object_unref (settings);
}
gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
}
static gboolean
ece_event_fill_component (ECompEditor *comp_editor,
icalcomponent *component)
{
ECompEditorEvent *event_editor;
gboolean date_valid, time_valid;
icalproperty *dtstart_prop, *dtend_prop;
icalproperty *prop;
icalproperty_class class_value;
g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE);
g_return_val_if_fail (component != NULL, FALSE);
if (!E_COMP_EDITOR_CLASS (e_comp_editor_event_parent_class)->fill_component (comp_editor, component))
return FALSE;
event_editor = E_COMP_EDITOR_EVENT (comp_editor);
if (!e_comp_editor_property_part_datetime_check_validity (
E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtstart), &date_valid, &time_valid)) {
const gchar *error_message = NULL;
if (!date_valid)
error_message = g_strdup (_("Start date is not a valid date"));
else if (!time_valid)
error_message = g_strdup (_("Start time is not a valid time"));
e_comp_editor_set_validation_error (comp_editor, event_editor->priv->page_general,
e_comp_editor_property_part_get_edit_widget (event_editor->priv->dtstart),
error_message ? error_message : _("Unknown error"));
return FALSE;
}
if (!e_comp_editor_property_part_datetime_check_validity (
E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtend), &date_valid, &time_valid)) {
const gchar *error_message = NULL;
if (!date_valid)
error_message = g_strdup (_("End date is not a valid date"));
else if (!time_valid)
error_message = g_strdup (_("End time is not a valid time"));
e_comp_editor_set_validation_error (comp_editor, event_editor->priv->page_general,
e_comp_editor_property_part_get_edit_widget (event_editor->priv->dtend),
error_message ? error_message : _("Unknown error"));
return FALSE;
}
dtstart_prop = icalcomponent_get_first_property (component, ICAL_DTSTART_PROPERTY);
dtend_prop = icalcomponent_get_first_property (component, ICAL_DTEND_PROPERTY);
if (dtstart_prop && dtend_prop) {
struct icaltimetype dtstart, dtend;
gboolean set_dtstart = FALSE, set_dtend = FALSE;
dtstart = icalproperty_get_dtstart (dtstart_prop);
dtend = icalproperty_get_dtend (dtend_prop);
if (dtstart.is_date && dtend.is_date) {
ECalClient *client;
/* Add 1 day to DTEND, as it is not inclusive. */
icaltime_adjust (&dtend, 1, 0, 0, 0);
set_dtend = TRUE;
client = e_comp_editor_get_target_client (comp_editor);
if (client && e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_ALL_DAY_EVENT_AS_TIME)) {
ECompEditorEvent *event_editor = E_COMP_EDITOR_EVENT (comp_editor);
GtkWidget *timezone_entry;
dtstart.is_date = FALSE;
dtstart.hour = 0;
dtstart.minute = 0;
dtstart.second = 0;
dtend.is_date = FALSE;
dtend.hour = 0;
dtend.minute = 0;
dtend.second = 0;
timezone_entry = e_comp_editor_property_part_get_edit_widget (event_editor->priv->timezone);
dtstart.zone = e_timezone_entry_get_timezone (E_TIMEZONE_ENTRY (timezone_entry));
if (!dtstart.zone)
dtstart.zone = icaltimezone_get_utc_timezone ();
dtend.zone = dtstart.zone;
set_dtstart = TRUE;
set_dtend = TRUE;
}
}
if (set_dtstart) {
icalproperty_set_dtstart (dtstart_prop, dtstart);
cal_comp_util_update_tzid_parameter (dtstart_prop, dtstart);
}
if (set_dtend) {
icalproperty_set_dtend (dtend_prop, dtend);
cal_comp_util_update_tzid_parameter (dtend_prop, dtend);
}
}
if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (
e_comp_editor_get_action (comp_editor, "classify-private"))))
class_value = ICAL_CLASS_PRIVATE;
else if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (
e_comp_editor_get_action (comp_editor, "classify-confidential"))))
class_value = ICAL_CLASS_CONFIDENTIAL;
else
class_value = ICAL_CLASS_PUBLIC;
prop = icalcomponent_get_first_property (component, ICAL_CLASS_PROPERTY);
if (prop) {
icalproperty_set_class (prop, class_value);
} else {
prop = icalproperty_new_class (class_value);
icalcomponent_add_property (component, prop);
}
return TRUE;
}
static void
ece_event_notify_source_client_cb (GObject *object,
GParamSpec *param,
gpointer user_data)
{
g_return_if_fail (E_IS_COMP_EDITOR_EVENT (object));
ece_event_update_timezone (E_COMP_EDITOR_EVENT (object), NULL, NULL);
}
static void
ece_event_setup_ui (ECompEditorEvent *event_editor)
{
const gchar *ui =
"<ui>"
" <menubar action='main-menu'>"
" <menu action='view-menu'>"
" <placeholder name='parts'>"
" <menuitem action='view-timezone'/>"
" <menuitem action='view-categories'/>"
" </placeholder>"
" </menu>"
" <menu action='options-menu'>"
" <placeholder name='toggles'>"
" <menuitem action='all-day-event'/>"
" <menuitem action='show-time-busy'/>"
" <menu action='classification-menu'>"
" <menuitem action='classify-public'/>"
" <menuitem action='classify-private'/>"
" <menuitem action='classify-confidential'/>"
" </menu>"
" </placeholder>"
" </menu>"
" </menubar>"
" <toolbar name='main-toolbar'>"
" <placeholder name='content'>\n"
" <toolitem action='all-day-event'/>\n"
" <toolitem action='show-time-busy'/>\n"
" </placeholder>"
" </toolbar>"
"</ui>";
const GtkToggleActionEntry view_actions[] = {
{ "view-categories",
NULL,
N_("_Categories"),
NULL,
N_("Toggles whether to display categories"),
NULL,
FALSE },
{ "view-timezone",
"stock_timezone",
N_("Time _Zone"),
NULL,
N_("Toggles whether the time zone is displayed"),
NULL,
FALSE },
{ "all-day-event",
"stock_new-24h-appointment",
N_("All _Day Event"),
NULL,
N_("Toggles whether to have All Day Event"),
NULL,
FALSE },
{ "show-time-busy",
"dialog-error",
N_("Show Time as _Busy"),
NULL,
N_("Toggles whether to show time as busy"),
NULL,
FALSE }
};
const GtkRadioActionEntry classification_radio_entries[] = {
{ "classify-public",
NULL,
N_("Pu_blic"),
NULL,
N_("Classify as public"),
ICAL_CLASS_PUBLIC },
{ "classify-private",
NULL,
N_("_Private"),
NULL,
N_("Classify as private"),
ICAL_CLASS_PRIVATE },
{ "classify-confidential",
NULL,
N_("_Confidential"),
NULL,
N_("Classify as confidential"),
ICAL_CLASS_CONFIDENTIAL }
};
ECompEditor *comp_editor;
GSettings *settings;
GtkUIManager *ui_manager;
GtkAction *action;
GtkActionGroup *action_group;
GtkWidget *widget;
GError *error = NULL;
g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor));
comp_editor = E_COMP_EDITOR (event_editor);
settings = e_comp_editor_get_settings (comp_editor);
ui_manager = e_comp_editor_get_ui_manager (comp_editor);
action_group = e_comp_editor_get_action_group (comp_editor, "individual");
gtk_action_group_add_toggle_actions (action_group,
view_actions, G_N_ELEMENTS (view_actions), event_editor);
gtk_action_group_add_radio_actions (
action_group, classification_radio_entries,
G_N_ELEMENTS (classification_radio_entries),
ICAL_CLASS_PUBLIC,
G_CALLBACK (ece_event_action_classification_cb), event_editor);
gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
e_plugin_ui_register_manager (ui_manager, "org.gnome.evolution.event-editor", event_editor);
e_plugin_ui_enable_manager (ui_manager, "org.gnome.evolution.event-editor");
if (error) {
g_critical ("%s: %s", G_STRFUNC, error->message);
g_error_free (error);
}
action = e_comp_editor_get_action (comp_editor, "view-categories");
e_binding_bind_property (
event_editor->priv->categories, "visible",
action, "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
g_settings_bind (
settings, "editor-show-categories",
action, "active",
G_SETTINGS_BIND_DEFAULT);
action = e_comp_editor_get_action (comp_editor, "view-timezone");
e_binding_bind_property (
event_editor->priv->timezone, "visible",
action, "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
g_settings_bind (
settings, "editor-show-timezone",
action, "active",
G_SETTINGS_BIND_DEFAULT);
action = e_comp_editor_get_action (comp_editor, "all-day-event");
e_binding_bind_property (
event_editor->priv->all_day_check, "active",
action, "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->transparency);
action = e_comp_editor_get_action (comp_editor, "show-time-busy");
e_binding_bind_property (
widget, "active",
action, "active",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
}
static void
e_comp_editor_event_constructed (GObject *object)
{
ECompEditor *comp_editor;
ECompEditorEvent *event_editor;
ECompEditorPage *page;
ECompEditorPropertyPart *part;
ECompEditorPropertyPart *summary;
EFocusTracker *focus_tracker;
GtkWidget *widget;
G_OBJECT_CLASS (e_comp_editor_event_parent_class)->constructed (object);
event_editor = E_COMP_EDITOR_EVENT (object);
comp_editor = E_COMP_EDITOR (event_editor);
focus_tracker = e_comp_editor_get_focus_tracker (comp_editor);
page = e_comp_editor_page_general_new (comp_editor,
_("_Calendar:"), E_SOURCE_EXTENSION_CALENDAR,
NULL, FALSE, 2);
event_editor->priv->page_general = page;
part = e_comp_editor_property_part_summary_new (focus_tracker);
e_comp_editor_page_add_property_part (page, part, 0, 2, 3, 1);
summary = part;
part = e_comp_editor_property_part_location_new (focus_tracker);
e_comp_editor_page_add_property_part (page, part, 0, 3, 3, 1);
part = e_comp_editor_property_part_dtstart_new (C_("ECompEditor", "_Start time:"), FALSE, FALSE);
e_comp_editor_page_add_property_part (page, part, 0, 4, 2, 1);
e_comp_editor_property_part_set_sensitize_handled (part, TRUE);
event_editor->priv->dtstart = part;
part = e_comp_editor_property_part_dtend_new (C_("ECompEditor", "_End time:"), FALSE, FALSE);
e_comp_editor_page_add_property_part (page, part, 0, 5, 2, 1);
e_comp_editor_property_part_set_sensitize_handled (part, TRUE);
event_editor->priv->dtend = part;
part = e_comp_editor_property_part_timezone_new ();
e_comp_editor_page_add_property_part (page, part, 0, 6, 3, 1);
e_comp_editor_property_part_set_sensitize_handled (part, TRUE);
event_editor->priv->timezone = part;
widget = gtk_check_button_new_with_mnemonic (C_("ECompEditor", "All da_y event"));
g_object_set (G_OBJECT (widget),
"hexpand", TRUE,
"halign", GTK_ALIGN_FILL,
"vexpand", FALSE,
"valign", GTK_ALIGN_START,
NULL);
gtk_grid_attach (GTK_GRID (page), widget, 2, 4, 1, 1);
gtk_widget_show (widget);
event_editor->priv->all_day_check = widget;
part = e_comp_editor_property_part_transparency_new ();
e_comp_editor_page_add_property_part (page, part, 2, 5, 1, 1);
event_editor->priv->transparency = part;
widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->transparency);
/* Transparency checkbox is not shown in the page, even it's packed there */
gtk_widget_hide (widget);
part = e_comp_editor_property_part_categories_new (focus_tracker);
e_comp_editor_page_add_property_part (page, part, 0, 7, 3, 1);
event_editor->priv->categories = part;
part = e_comp_editor_property_part_description_new (focus_tracker);
e_comp_editor_page_add_property_part (page, part, 0, 8, 3, 1);
event_editor->priv->description = part;
widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->timezone);
e_comp_editor_property_part_datetime_attach_timezone_entry (
E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtstart),
E_TIMEZONE_ENTRY (widget));
e_comp_editor_property_part_datetime_attach_timezone_entry (
E_COMP_EDITOR_PROPERTY_PART_DATETIME (event_editor->priv->dtend),
E_TIMEZONE_ENTRY (widget));
e_comp_editor_set_time_parts (comp_editor, event_editor->priv->dtstart, event_editor->priv->dtend);
widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->dtstart);
e_binding_bind_property (
event_editor->priv->all_day_check, "active",
widget, "show-time",
G_BINDING_INVERT_BOOLEAN | G_BINDING_BIDIRECTIONAL);
g_signal_connect (widget, "changed", G_CALLBACK (ece_event_dtstart_changed_cb), event_editor);
widget = e_comp_editor_property_part_get_edit_widget (event_editor->priv->dtend);
e_binding_bind_property (
event_editor->priv->all_day_check, "active",
widget, "show-time",
G_BINDING_INVERT_BOOLEAN | G_BINDING_BIDIRECTIONAL);
g_signal_connect (widget, "changed", G_CALLBACK (ece_event_dtend_changed_cb), event_editor);
e_signal_connect_notify_swapped (event_editor->priv->all_day_check, "notify::active",
G_CALLBACK (ece_event_all_day_toggled_cb), event_editor);
e_comp_editor_add_page (comp_editor, C_("ECompEditorPage", "General"), page);
page = e_comp_editor_page_reminders_new (comp_editor);
e_comp_editor_add_page (comp_editor, C_("ECompEditorPage", "Reminders"), page);
page = e_comp_editor_page_recurrence_new (comp_editor);
e_comp_editor_add_page (comp_editor, C_("ECompEditorPage", "Recurrence"), page);
page = e_comp_editor_page_attachments_new (comp_editor);
e_comp_editor_add_page (comp_editor, C_("ECompEditorPage", "Attachments"), page);
page = e_comp_editor_page_schedule_new (comp_editor,
e_comp_editor_page_general_get_meeting_store (
E_COMP_EDITOR_PAGE_GENERAL (event_editor->priv->page_general)));
e_binding_bind_property (
event_editor->priv->page_general, "show-attendees",
page, "visible",
G_BINDING_SYNC_CREATE);
e_comp_editor_add_page (comp_editor, C_("ECompEditorPage", "Schedule"), page);
ece_event_setup_ui (event_editor);
widget = e_comp_editor_property_part_get_edit_widget (summary);
e_binding_bind_property (widget, "text", comp_editor, "title-suffix", 0);
/* Do this as the last thing, because some widgets can call the function as well */
gtk_widget_grab_focus (widget);
g_signal_connect (comp_editor, "notify::source-client",
G_CALLBACK (ece_event_notify_source_client_cb), NULL);
}
static void
e_comp_editor_event_init (ECompEditorEvent *event_editor)
{
event_editor->priv = G_TYPE_INSTANCE_GET_PRIVATE (event_editor, E_TYPE_COMP_EDITOR_EVENT, ECompEditorEventPrivate);
}
static void
e_comp_editor_event_class_init (ECompEditorEventClass *klass)
{
GObjectClass *object_class;
ECompEditorClass *comp_editor_class;
g_type_class_add_private (klass, sizeof (ECompEditorEventPrivate));
object_class = G_OBJECT_CLASS (klass);
object_class->constructed = e_comp_editor_event_constructed;
comp_editor_class = E_COMP_EDITOR_CLASS (klass);
comp_editor_class->help_section = "calendar-usage-add-appointment";
comp_editor_class->title_format_with_attendees = _("Meeting — %s");
comp_editor_class->title_format_without_attendees = _("Appointment — %s");
comp_editor_class->icon_name = "appointment-new";
comp_editor_class->sensitize_widgets = ece_event_sensitize_widgets;
comp_editor_class->fill_widgets = ece_event_fill_widgets;
comp_editor_class->fill_component = ece_event_fill_component;
}