aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/gui/dialogs/task-page.c
diff options
context:
space:
mode:
Diffstat (limited to 'calendar/gui/dialogs/task-page.c')
-rw-r--r--calendar/gui/dialogs/task-page.c522
1 files changed, 522 insertions, 0 deletions
diff --git a/calendar/gui/dialogs/task-page.c b/calendar/gui/dialogs/task-page.c
index 1eb5f00354..fcc00fae5d 100644
--- a/calendar/gui/dialogs/task-page.c
+++ b/calendar/gui/dialogs/task-page.c
@@ -78,9 +78,16 @@ struct _TaskPagePrivate {
GtkWidget *due_date;
GtkWidget *start_date;
+ GtkWidget *completed_date;
GtkWidget *timezone;
GtkWidget *timezone_label;
+ GtkWidget *status_combo;
+ GtkWidget *priority_combo;
+ GtkWidget *percent_complete;
+ GtkWidget *classification_combo;
+ GtkWidget *web_page_entry;
+
GtkWidget *description;
GtkWidget *categories_btn;
@@ -123,12 +130,79 @@ static const gint classification_map[] = {
-1
};
+/* Note that these two arrays must match. */
+static const gint status_map[] = {
+ ICAL_STATUS_NONE,
+ ICAL_STATUS_INPROCESS,
+ ICAL_STATUS_COMPLETED,
+ ICAL_STATUS_CANCELLED,
+ -1
+};
+
+typedef enum {
+ PRIORITY_HIGH,
+ PRIORITY_NORMAL,
+ PRIORITY_LOW,
+ PRIORITY_UNDEFINED
+} TaskEditorPriority;
+
+static const gint priority_map[] = {
+ PRIORITY_HIGH,
+ PRIORITY_NORMAL,
+ PRIORITY_LOW,
+ PRIORITY_UNDEFINED,
+ -1
+};
+
static gboolean task_page_fill_timezones (CompEditorPage *page, GHashTable *timezones);
static void task_page_select_organizer (TaskPage *tpage, const gchar *backend_address);
static void set_subscriber_info_string (TaskPage *tpage, const gchar *backend_address);
G_DEFINE_TYPE (TaskPage, task_page, TYPE_COMP_EDITOR_PAGE)
+static TaskEditorPriority
+priority_value_to_index (gint priority_value)
+{
+ TaskEditorPriority retval;
+
+ if (priority_value == 0)
+ retval = PRIORITY_UNDEFINED;
+ else if (priority_value <= 4)
+ retval = PRIORITY_HIGH;
+ else if (priority_value == 5)
+ retval = PRIORITY_NORMAL;
+ else
+ retval = PRIORITY_LOW;
+
+ return retval;
+}
+
+static gint
+priority_index_to_value (TaskEditorPriority priority)
+{
+ gint retval;
+
+ switch (priority) {
+ case PRIORITY_UNDEFINED:
+ retval = 0;
+ break;
+ case PRIORITY_HIGH:
+ retval = 3;
+ break;
+ case PRIORITY_NORMAL:
+ retval = 5;
+ break;
+ case PRIORITY_LOW:
+ retval = 7;
+ break;
+ default:
+ retval = 0;
+ break;
+ }
+
+ return retval;
+}
+
static gboolean
get_current_identity (TaskPage *page,
gchar **name,
@@ -194,6 +268,7 @@ clear_widgets (TaskPage *tpage)
{
TaskPagePrivate *priv = tpage->priv;
CompEditor *editor;
+ GtkWidget *entry;
editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (tpage));
@@ -211,6 +286,14 @@ clear_widgets (TaskPage *tpage)
/* Categories */
gtk_entry_set_text (GTK_ENTRY (priv->categories), "");
+
+ e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), -1);
+ e_dialog_combo_box_set (priv->status_combo, ICAL_STATUS_NONE, status_map);
+ e_dialog_combo_box_set (priv->priority_combo, PRIORITY_UNDEFINED, priority_map);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->percent_complete), 0);
+
+ entry = e_url_entry_get_entry (E_URL_ENTRY (priv->web_page_entry));
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
}
static gboolean
@@ -266,6 +349,7 @@ sensitize_widgets (TaskPage *tpage)
ECalClient *client;
GtkActionGroup *action_group;
GtkAction *action;
+ GtkWidget *entry;
gboolean read_only, sens = TRUE, sensitize;
editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (tpage));
@@ -310,6 +394,15 @@ sensitize_widgets (TaskPage *tpage)
gtk_widget_set_sensitive (priv->categories_btn, !read_only);
gtk_editable_set_editable (GTK_EDITABLE (priv->categories), !read_only);
+ gtk_widget_set_sensitive (priv->completed_date, !read_only);
+ gtk_widget_set_sensitive (priv->status_combo, !read_only);
+ gtk_widget_set_sensitive (priv->priority_combo, !read_only);
+ gtk_widget_set_sensitive (priv->percent_complete, !read_only);
+ gtk_widget_set_sensitive (priv->classification_combo, !read_only);
+
+ entry = e_url_entry_get_entry (E_URL_ENTRY (priv->web_page_entry));
+ gtk_editable_set_editable (GTK_EDITABLE (entry), !read_only);
+
gtk_widget_set_sensitive (priv->organizer, !read_only);
gtk_widget_set_sensitive (priv->add, (!read_only && sens));
gtk_widget_set_sensitive (priv->edit, (!read_only && sens));
@@ -492,6 +585,11 @@ task_page_fill_widgets (CompEditorPage *page,
icaltimezone *zone, *default_zone;
gchar *backend_addr = NULL;
gboolean active;
+ gint *priority_value, *percent = NULL;
+ TaskEditorPriority priority;
+ icalproperty_status status;
+ const gchar *url;
+ struct icaltimetype *completed = NULL;
tpage = TASK_PAGE (page);
priv = tpage->priv;
@@ -754,6 +852,74 @@ task_page_fill_widgets (CompEditorPage *page,
g_free (backend_addr);
+ /* Percent Complete. */
+ e_cal_component_get_percent (comp, &percent);
+ if (percent) {
+ gtk_spin_button_set_value (
+ GTK_SPIN_BUTTON (priv->percent_complete), *percent);
+ } else {
+ /* FIXME: Could check if task is completed and set 100%. */
+ gtk_spin_button_set_value (
+ GTK_SPIN_BUTTON (priv->percent_complete), 0);
+ }
+
+ /* Status. */
+ e_cal_component_get_status (comp, &status);
+ if (status == ICAL_STATUS_NONE || status == ICAL_STATUS_NEEDSACTION) {
+ /* Try to use the percent value. */
+ if (percent) {
+ if (*percent == 100)
+ status = ICAL_STATUS_COMPLETED;
+ else if (*percent > 0)
+ status = ICAL_STATUS_INPROCESS;
+ else
+ status = ICAL_STATUS_NONE;
+ } else
+ status = ICAL_STATUS_NONE;
+ }
+ e_dialog_combo_box_set (priv->status_combo, status, status_map);
+
+ if (percent)
+ e_cal_component_free_percent (percent);
+
+ /* Completed Date. */
+ e_cal_component_get_completed (comp, &completed);
+ if (completed) {
+ icaltimezone *utc_zone, *zone;
+
+ /* Completed is in UTC, but that would confuse the user, so
+ * we convert it to local time. */
+ utc_zone = icaltimezone_get_utc_timezone ();
+ zone = comp_editor_get_timezone (editor);
+
+ icaltimezone_convert_time (completed, utc_zone, zone);
+
+ e_date_edit_set_date (
+ E_DATE_EDIT (priv->completed_date),
+ completed->year, completed->month,
+ completed->day);
+ e_date_edit_set_time_of_day (
+ E_DATE_EDIT (priv->completed_date),
+ completed->hour,
+ completed->minute);
+
+ e_cal_component_free_icaltimetype (completed);
+ }
+
+ /* Priority. */
+ e_cal_component_get_priority (comp, &priority_value);
+ if (priority_value) {
+ priority = priority_value_to_index (*priority_value);
+ e_cal_component_free_priority (priority_value);
+ } else {
+ priority = PRIORITY_UNDEFINED;
+ }
+ e_dialog_combo_box_set (priv->priority_combo, priority, priority_map);
+
+ /* URL */
+ e_cal_component_get_url (comp, &url);
+ gtk_entry_set_text (GTK_ENTRY (e_url_entry_get_entry (E_URL_ENTRY (priv->web_page_entry))), url ? url : "");
+
sensitize_widgets (tpage);
return TRUE;
@@ -775,6 +941,13 @@ task_page_fill_component (CompEditorPage *page,
gboolean start_date_set, due_date_set;
GtkTextBuffer *text_buffer;
GtkTextIter text_iter_start, text_iter_end;
+ struct icaltimetype icalcomplete, icaltoday;
+ icalproperty_status status;
+ TaskEditorPriority priority;
+ gint priority_value, percent;
+ const gchar *text;
+ gboolean date_set;
+ icaltimezone *zone;
tpage = TASK_PAGE (page);
priv = tpage->priv;
@@ -783,6 +956,7 @@ task_page_fill_component (CompEditorPage *page,
editor = comp_editor_page_get_editor (page);
client = comp_editor_get_client (editor);
flags = comp_editor_get_flags (editor);
+ zone = comp_editor_get_timezone (editor);
/* Summary. */
@@ -976,6 +1150,77 @@ task_page_fill_component (CompEditorPage *page,
set_attendees (comp, e_meeting_store_get_attendees (priv->meeting_store));
}
+ /* Percent Complete. */
+ percent = gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (priv->percent_complete));
+ e_cal_component_set_percent (comp, &percent);
+
+ /* Status. */
+ status = e_dialog_combo_box_get (priv->status_combo, status_map);
+ e_cal_component_set_status (comp, status);
+
+ /* Priority. */
+ priority = e_dialog_combo_box_get (priv->priority_combo, priority_map);
+ priority_value = priority_index_to_value (priority);
+ e_cal_component_set_priority (comp, &priority_value);
+
+ icalcomplete = icaltime_null_time ();
+
+ /* COMPLETED must be in UTC. */
+ icalcomplete.is_utc = 1;
+
+ /* Completed Date. */
+ if (!e_date_edit_date_is_valid (E_DATE_EDIT (priv->completed_date)) ||
+ !e_date_edit_time_is_valid (E_DATE_EDIT (priv->completed_date))) {
+ comp_editor_page_display_validation_error (
+ page, _("Completed date is wrong"),
+ priv->completed_date);
+ return FALSE;
+ }
+
+ date_set = e_date_edit_get_date (
+ E_DATE_EDIT (priv->completed_date),
+ &icalcomplete.year,
+ &icalcomplete.month,
+ &icalcomplete.day);
+
+ if (date_set) {
+ e_date_edit_get_time_of_day (
+ E_DATE_EDIT (priv->completed_date),
+ &icalcomplete.hour,
+ &icalcomplete.minute);
+
+ /* COMPLETED today or before */
+ icaltoday = icaltime_current_time_with_zone (zone);
+ icaltimezone_convert_time (
+ &icaltoday, zone,
+ icaltimezone_get_utc_timezone ());
+
+ if (icaltime_compare_date_only (icalcomplete, icaltoday) > 0) {
+ comp_editor_page_display_validation_error (
+ page, _("Completed date is wrong"),
+ priv->completed_date);
+ return FALSE;
+ }
+
+ /* COMPLETED must be in UTC, so we assume that the date in the
+ * dialog is in the current timezone, and we now convert it
+ * to UTC. FIXME: We should really use one timezone for the
+ * entire time the dialog is shown. Otherwise if the user
+ * changes the timezone, the COMPLETED date may get changed
+ * as well. */
+ icaltimezone_convert_time (
+ &icalcomplete, zone,
+ icaltimezone_get_utc_timezone ());
+ e_cal_component_set_completed (comp, &icalcomplete);
+ } else {
+ e_cal_component_set_completed (comp, NULL);
+ }
+
+ /* URL. */
+ text = gtk_entry_get_text (GTK_ENTRY (e_url_entry_get_entry (E_URL_ENTRY (priv->web_page_entry))));
+ e_cal_component_set_url (comp, text);
+
return TRUE;
}
@@ -997,6 +1242,16 @@ task_page_fill_timezones (CompEditorPage *page,
g_hash_table_insert (timezones, (gpointer) icaltimezone_get_tzid (zone), zone);
}
+ /* Add UTC timezone, which is the one
+ * used for the DATE-COMPLETED property. */
+ zone = icaltimezone_get_utc_timezone ();
+ if (zone != NULL) {
+ gconstpointer tzid = icaltimezone_get_tzid (zone);
+
+ if (!g_hash_table_lookup (timezones, tzid))
+ g_hash_table_insert (timezones, (gpointer) tzid, zone);
+ }
+
return TRUE;
}
@@ -1495,6 +1750,13 @@ get_widgets (TaskPage *tpage)
priv->start_date = e_builder_get_widget (priv->builder, "start-date");
gtk_widget_show (priv->start_date);
+ priv->completed_date = e_builder_get_widget (priv->builder, "completed-date");
+ priv->status_combo = e_builder_get_widget (priv->builder, "status-combobox");
+ priv->priority_combo = e_builder_get_widget (priv->builder, "priority-combobox");
+ priv->percent_complete = e_builder_get_widget (priv->builder, "percent-complete");
+ priv->classification_combo = e_builder_get_widget (priv->builder, "classification-combobox");
+ priv->web_page_entry = e_builder_get_widget (priv->builder, "web-page-entry");
+
priv->timezone = e_builder_get_widget (priv->builder, "timezone");
priv->timezone_label = e_builder_get_widget (priv->builder, "timezone-label");
priv->attendees_label = e_builder_get_widget (priv->builder, "attendees-label");
@@ -1548,6 +1810,12 @@ get_widgets (TaskPage *tpage)
&& priv->categories_btn
&& priv->categories
&& priv->organizer
+ && priv->completed_date
+ && priv->status_combo
+ && priv->priority_combo
+ && priv->percent_complete
+ && priv->classification_combo
+ && priv->web_page_entry
);
}
@@ -1914,6 +2182,210 @@ task_page_send_options_clicked_cb (TaskPage *tpage)
e_send_options_dialog_run (priv->sod, toplevel, E_ITEM_TASK);
}
+static void
+complete_date_changed (TaskPage *tpage,
+ time_t ctime,
+ gboolean complete)
+{
+ CompEditorPageDates dates = {NULL, NULL, NULL, NULL};
+ icaltimezone *zone;
+ struct icaltimetype completed_tt = icaltime_null_time ();
+
+ /* Get the current time in UTC. */
+ zone = icaltimezone_get_utc_timezone ();
+ completed_tt = icaltime_from_timet_with_zone (ctime, FALSE, zone);
+ completed_tt.is_utc = TRUE;
+
+ dates.start = NULL;
+ dates.end = NULL;
+ dates.due = NULL;
+ if (complete)
+ dates.complete = &completed_tt;
+
+ /* Notify upstream */
+ comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (tpage),
+ &dates);
+}
+
+static void
+completed_date_changed_cb (EDateEdit *dedit,
+ TaskPage *tpage)
+{
+ TaskPagePrivate *priv = tpage->priv;
+ CompEditorPageDates dates = {NULL, NULL, NULL, NULL};
+ struct icaltimetype completed_tt = icaltime_null_time ();
+ icalproperty_status status;
+ gboolean date_set;
+
+ if (comp_editor_page_get_updating (COMP_EDITOR_PAGE (tpage)))
+ return;
+
+ comp_editor_page_set_updating (COMP_EDITOR_PAGE (tpage), TRUE);
+
+ date_set = e_date_edit_get_date (
+ E_DATE_EDIT (priv->completed_date),
+ &completed_tt.year,
+ &completed_tt.month,
+ &completed_tt.day);
+ e_date_edit_get_time_of_day (
+ E_DATE_EDIT (priv->completed_date),
+ &completed_tt.hour,
+ &completed_tt.minute);
+
+ status = e_dialog_combo_box_get (priv->status_combo, status_map);
+
+ if (!date_set) {
+ completed_tt = icaltime_null_time ();
+ if (status == ICAL_STATUS_COMPLETED) {
+ e_dialog_combo_box_set (
+ priv->status_combo,
+ ICAL_STATUS_NONE,
+ status_map);
+ gtk_spin_button_set_value (
+ GTK_SPIN_BUTTON (priv->percent_complete), 0);
+ }
+ } else {
+ if (status != ICAL_STATUS_COMPLETED) {
+ e_dialog_combo_box_set (
+ priv->status_combo,
+ ICAL_STATUS_COMPLETED,
+ status_map);
+ }
+ gtk_spin_button_set_value (
+ GTK_SPIN_BUTTON (priv->percent_complete), 100);
+ }
+
+ comp_editor_page_set_updating (COMP_EDITOR_PAGE (tpage), FALSE);
+
+ /* Notify upstream */
+ dates.complete = &completed_tt;
+ comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (tpage), &dates);
+}
+
+static void
+status_changed (GtkWidget *combo,
+ TaskPage *tpage)
+{
+ TaskPagePrivate *priv;
+ icalproperty_status status;
+ CompEditor *editor;
+ time_t ctime = -1;
+
+ priv = tpage->priv;
+
+ if (comp_editor_page_get_updating (COMP_EDITOR_PAGE (tpage)))
+ return;
+
+ editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (tpage));
+
+ comp_editor_page_set_updating (COMP_EDITOR_PAGE (tpage), TRUE);
+
+ status = e_dialog_combo_box_get (priv->status_combo, status_map);
+ if (status == ICAL_STATUS_NONE) {
+ gtk_spin_button_set_value (
+ GTK_SPIN_BUTTON (priv->percent_complete), 0);
+ e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), ctime);
+ complete_date_changed (tpage, 0, FALSE);
+ } else if (status == ICAL_STATUS_INPROCESS) {
+ gint percent_complete = gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (priv->percent_complete));
+ if (percent_complete <= 0 || percent_complete >= 100)
+ gtk_spin_button_set_value (
+ GTK_SPIN_BUTTON (priv->percent_complete), 50);
+
+ e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), ctime);
+ complete_date_changed (tpage, 0, FALSE);
+ } else if (status == ICAL_STATUS_COMPLETED) {
+ gtk_spin_button_set_value (
+ GTK_SPIN_BUTTON (priv->percent_complete), 100);
+ ctime = time (NULL);
+ e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), ctime);
+ complete_date_changed (tpage, ctime, TRUE);
+ }
+
+ comp_editor_page_set_updating (COMP_EDITOR_PAGE (tpage), FALSE);
+
+ comp_editor_set_changed (editor, TRUE);
+}
+
+static void
+percent_complete_changed (GtkAdjustment *adj,
+ TaskPage *tpage)
+{
+ TaskPagePrivate *priv;
+ gint percent;
+ icalproperty_status status;
+ CompEditor *editor;
+ gboolean complete;
+ time_t ctime = -1;
+
+ priv = tpage->priv;
+
+ if (comp_editor_page_get_updating (COMP_EDITOR_PAGE (tpage)))
+ return;
+
+ editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (tpage));
+
+ comp_editor_page_set_updating (COMP_EDITOR_PAGE (tpage), TRUE);
+
+ percent = gtk_spin_button_get_value_as_int (
+ GTK_SPIN_BUTTON (priv->percent_complete));
+ if (percent == 100) {
+ complete = TRUE;
+ ctime = time (NULL);
+ status = ICAL_STATUS_COMPLETED;
+ } else {
+ complete = FALSE;
+
+ if (percent == 0)
+ status = ICAL_STATUS_NONE;
+ else
+ status = ICAL_STATUS_INPROCESS;
+ }
+
+ e_dialog_combo_box_set (priv->status_combo, status, status_map);
+ e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), ctime);
+ complete_date_changed (tpage, ctime, complete);
+
+ comp_editor_page_set_updating (COMP_EDITOR_PAGE (tpage), FALSE);
+
+ comp_editor_set_changed (editor, TRUE);
+}
+
+static gboolean
+task_page_transform_classification_to_combo (GBinding *binding,
+ const GValue *source_value,
+ GValue *target_value,
+ gpointer user_data)
+{
+ gint action_value;
+
+ g_return_val_if_fail (source_value != NULL, FALSE);
+ g_return_val_if_fail (target_value != NULL, FALSE);
+
+ action_value = g_value_get_int (source_value);
+ g_value_set_int (target_value, action_value - 1);
+
+ return TRUE;
+}
+
+static gboolean
+task_page_transform_classification_from_combo (GBinding *binding,
+ const GValue *source_value,
+ GValue *target_value,
+ gpointer user_data)
+{
+ gint combo_value;
+
+ g_return_val_if_fail (source_value != NULL, FALSE);
+ g_return_val_if_fail (target_value != NULL, FALSE);
+
+ combo_value = g_value_get_int (source_value);
+ g_value_set_int (target_value, combo_value + 1);
+
+ return TRUE;
+}
+
/* Hooks the widget signals */
static gboolean
init_widgets (TaskPage *tpage)
@@ -1924,6 +2396,7 @@ init_widgets (TaskPage *tpage)
GtkTextBuffer *text_buffer;
icaltimezone *zone;
gboolean active;
+ GtkAdjustment *adjustment;
priv = tpage->priv;
@@ -2045,6 +2518,45 @@ init_widgets (TaskPage *tpage)
zone = comp_editor_get_timezone (editor);
e_timezone_entry_set_default_timezone (E_TIMEZONE_ENTRY (priv->timezone), zone);
+ /* Make sure the EDateEdit widgets use our timezones to get the
+ * current time. */
+ e_date_edit_set_get_time_callback (
+ E_DATE_EDIT (priv->completed_date),
+ (EDateEditGetTimeCallback) comp_editor_get_current_time,
+ g_object_ref (editor),
+ (GDestroyNotify) g_object_unref);
+
+ /* Connect signals. The Status, Percent Complete & Date Completed
+ * properties are closely related so whenever one changes we may need
+ * to update the other 2. */
+ g_signal_connect (
+ GTK_COMBO_BOX (priv->status_combo), "changed",
+ G_CALLBACK (status_changed), tpage);
+
+ adjustment = gtk_spin_button_get_adjustment (
+ GTK_SPIN_BUTTON (priv->percent_complete));
+ g_signal_connect (
+ adjustment, "value_changed",
+ G_CALLBACK (percent_complete_changed), tpage);
+
+ /* Priority */
+ g_signal_connect_swapped (
+ GTK_COMBO_BOX (priv->priority_combo), "changed",
+ G_CALLBACK (comp_editor_page_changed), tpage);
+
+ /* Completed Date */
+ g_signal_connect (
+ priv->completed_date, "changed",
+ G_CALLBACK (completed_date_changed_cb), tpage);
+ g_signal_connect_swapped (
+ priv->completed_date, "changed",
+ G_CALLBACK (comp_editor_page_changed), tpage);
+
+ /* URL */
+ g_signal_connect_swapped (
+ e_url_entry_get_entry (E_URL_ENTRY (priv->web_page_entry)), "changed",
+ G_CALLBACK (comp_editor_page_changed), tpage);
+
action = comp_editor_get_action (editor, "view-time-zone");
active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
task_page_set_show_timezone (tpage, active);
@@ -2076,6 +2588,16 @@ init_widgets (TaskPage *tpage)
active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
task_page_set_show_categories (tpage, active);
+ /* Classification */
+ action = comp_editor_get_action (editor, "classify-public");
+ g_object_bind_property_full (
+ action, "current-value",
+ priv->classification_combo, "active",
+ G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE,
+ task_page_transform_classification_to_combo,
+ task_page_transform_classification_from_combo,
+ NULL, NULL);
+
return TRUE;
}