diff options
Diffstat (limited to 'calendar/gui/dialogs/task-page.c')
-rw-r--r-- | calendar/gui/dialogs/task-page.c | 522 |
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; } |