/* gtd-task-eds.c * * Copyright (C) 2017-2020 Georges Basile Stavracas Neto * * 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, either version 3 of the License, or * (at your option) any later version. * * 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 . */ #define G_LOG_DOMAIN "GtdTaskEds" #include "gtd-eds-autoptr.h" #include "gtd-task-eds.h" #define ICAL_X_ENDEAVOUR_POSITION "X-ENDEAVOUR-POSITION" struct _GtdTaskEds { GtdTask parent; ECalComponent *component; ECalComponent *new_component; gchar *description; }; G_DEFINE_TYPE (GtdTaskEds, gtd_task_eds, GTD_TYPE_TASK) enum { PROP_0, PROP_COMPONENT, N_PROPS }; static GParamSpec *properties [N_PROPS]; /* * Auxiliary methods */ static GDateTime* convert_icaltime (const ICalTime *date) { GDateTime *dt; if (!date) return NULL; dt = g_date_time_new_utc (i_cal_time_get_year (date), i_cal_time_get_month (date), i_cal_time_get_day (date), i_cal_time_is_date (date) ? 0 : i_cal_time_get_hour (date), i_cal_time_is_date (date) ? 0 : i_cal_time_get_minute (date), i_cal_time_is_date (date) ? 0 : i_cal_time_get_second (date)); return dt; } static void set_description (GtdTaskEds *self, const gchar *description) { ECalComponentText *text; GSList note; text = e_cal_component_text_new (description ? description : "", NULL); note.data = text; note.next = NULL; g_clear_pointer (&self->description, g_free); self->description = g_strdup (description); e_cal_component_set_descriptions (self->new_component, (description && *description) ? ¬e : NULL); e_cal_component_text_free (text); } static void setup_description (GtdTaskEds *self) { g_autofree gchar *desc = NULL; GSList *text_list; GSList *l; /* concatenates the multiple descriptions a task may have */ text_list = e_cal_component_get_descriptions (self->new_component); for (l = text_list; l != NULL; l = l->next) { if (l->data != NULL) { ECalComponentText *text; gchar *carrier; text = l->data; if (desc) { carrier = g_strconcat (desc, "\n", e_cal_component_text_get_value (text), NULL); g_free (desc); desc = carrier; } else { desc = g_strdup (e_cal_component_text_get_value (text)); } } } set_description (self, desc); g_slist_free_full (text_list, e_cal_component_text_free); } /* * GtdObject overrides */ static const gchar* gtd_task_eds_get_uid (GtdObject *object) { GtdTaskEds *self; const gchar *uid; g_return_val_if_fail (GTD_IS_TASK (object), NULL); self = GTD_TASK_EDS (object); if (self->new_component) uid = e_cal_component_get_uid (self->new_component); else uid = NULL; return uid; } static void gtd_task_eds_set_uid (GtdObject *object, const gchar *uid) { GtdTaskEds *self; const gchar *current_uid; g_return_if_fail (GTD_IS_TASK (object)); self = GTD_TASK_EDS (object); if (!self->new_component) return; current_uid = e_cal_component_get_uid (self->new_component); if (g_strcmp0 (current_uid, uid) != 0) { e_cal_component_set_uid (self->new_component, uid); g_object_notify (G_OBJECT (object), "uid"); } } /* * GtdTask overrides */ static GDateTime* gtd_task_eds_get_completion_date (GtdTask *task) { ICalTime *idt; GtdTaskEds *self; GDateTime *dt; self = GTD_TASK_EDS (task); dt = NULL; idt = e_cal_component_get_completed (self->new_component); if (idt) dt = convert_icaltime (idt); g_clear_object (&idt); return dt; } static void gtd_task_eds_set_completion_date (GtdTask *task, GDateTime *dt) { GtdTaskEds *self; ICalTime *idt; self = GTD_TASK_EDS (task); idt = i_cal_time_new_null_time (); i_cal_time_set_date (idt, g_date_time_get_year (dt), g_date_time_get_month (dt), g_date_time_get_day_of_month (dt)); i_cal_time_set_time (idt, g_date_time_get_hour (dt), g_date_time_get_minute (dt), g_date_time_get_seconds (dt)); i_cal_time_set_timezone (idt, i_cal_timezone_get_utc_timezone ()); /* convert timezone * * FIXME: This does not do anything until we have an ical * timezone associated with the task */ i_cal_time_convert_timezone (idt, NULL, i_cal_timezone_get_utc_timezone ()); e_cal_component_set_completed (self->new_component, idt); g_object_unref (idt); } static gboolean gtd_task_eds_get_complete (GtdTask *task) { ICalPropertyStatus status; GtdTaskEds *self; gboolean completed; g_return_val_if_fail (GTD_IS_TASK_EDS (task), FALSE); self = GTD_TASK_EDS (task); status = e_cal_component_get_status (self->new_component); completed = status == I_CAL_STATUS_COMPLETED; return completed; } static void gtd_task_eds_set_complete (GtdTask *task, gboolean complete) { ICalPropertyStatus status; GtdTaskEds *self; gint percent; g_autoptr (GDateTime) now = NULL; self = GTD_TASK_EDS (task); now = complete ? g_date_time_new_now_local () : NULL; if (complete) { percent = 100; status = I_CAL_STATUS_COMPLETED; } else { percent = 0; status = I_CAL_STATUS_NEEDSACTION; } e_cal_component_set_percent_complete (self->new_component, percent); e_cal_component_set_status (self->new_component, status); gtd_task_eds_set_completion_date (task, now); } static GDateTime* gtd_task_eds_get_creation_date (GtdTask *task) { ICalTime *idt; GtdTaskEds *self; GDateTime *dt; self = GTD_TASK_EDS (task); dt = NULL; idt = e_cal_component_get_created (self->new_component); if (idt) dt = convert_icaltime (idt); g_clear_object (&idt); return dt; } static void gtd_task_eds_set_creation_date (GtdTask *task, GDateTime *dt) { g_assert_not_reached (); } static const gchar* gtd_task_eds_get_description (GtdTask *task) { GtdTaskEds *self = GTD_TASK_EDS (task); return self->description ? self->description : ""; } static void gtd_task_eds_set_description (GtdTask *task, const gchar *description) { set_description (GTD_TASK_EDS (task), description); } static GDateTime* gtd_task_eds_get_due_date (GtdTask *task) { ECalComponentDateTime *comp_dt; GtdTaskEds *self; GDateTime *date; g_return_val_if_fail (GTD_IS_TASK_EDS (task), NULL); self = GTD_TASK_EDS (task); comp_dt = e_cal_component_get_due (self->new_component); if (!comp_dt) return NULL; date = convert_icaltime (e_cal_component_datetime_get_value (comp_dt)); e_cal_component_datetime_free (comp_dt); return date; } static void gtd_task_eds_set_due_date (GtdTask *task, GDateTime *dt) { GtdTaskEds *self; GDateTime *current_dt; g_assert (GTD_IS_TASK_EDS (task)); self = GTD_TASK_EDS (task); current_dt = gtd_task_get_due_date (task); if (dt != current_dt) { ECalComponentDateTime *comp_dt; ICalTime *idt; comp_dt = NULL; idt = NULL; if (!current_dt || (current_dt && dt && g_date_time_compare (current_dt, dt) != 0)) { idt = i_cal_time_new_null_time (); g_date_time_ref (dt); /* Copy the given dt */ i_cal_time_set_date (idt, g_date_time_get_year (dt), g_date_time_get_month (dt), g_date_time_get_day_of_month (dt)); i_cal_time_set_time (idt, g_date_time_get_hour (dt), g_date_time_get_minute (dt), g_date_time_get_seconds (dt)); i_cal_time_set_is_date (idt, i_cal_time_get_hour (idt) == 0 && i_cal_time_get_minute (idt) == 0 && i_cal_time_get_second (idt) == 0); comp_dt = e_cal_component_datetime_new_take (idt, g_strdup ("UTC")); e_cal_component_set_due (self->new_component, comp_dt); e_cal_component_datetime_free (comp_dt); g_date_time_unref (dt); } else if (!dt) { e_cal_component_set_due (self->new_component, NULL); } } g_clear_pointer (¤t_dt, g_date_time_unref); } static gboolean gtd_task_eds_get_important (GtdTask *task) { GtdTaskEds *self = GTD_TASK_EDS (task); return e_cal_component_get_priority (self->new_component) > 0; } static void gtd_task_eds_set_important (GtdTask *task, gboolean important) { GtdTaskEds *self = GTD_TASK_EDS (task); e_cal_component_set_priority (self->new_component, important ? 3 : -1); } static gint64 gtd_task_eds_get_position (GtdTask *task) { g_autofree gchar *value = NULL; ICalComponent *ical_comp; gint64 position = -1; GtdTaskEds *self; self = GTD_TASK_EDS (task); ical_comp = e_cal_component_get_icalcomponent (self->new_component); value = e_cal_util_component_dup_x_property (ical_comp, ICAL_X_ENDEAVOUR_POSITION); if (value) position = g_ascii_strtoll (value, NULL, 10); return position; } void gtd_task_eds_set_position (GtdTask *task, gint64 position) { g_autofree gchar *value = NULL; ICalComponent *ical_comp; GtdTaskEds *self; self = GTD_TASK_EDS (task); if (position != -1) value = g_strdup_printf ("%" G_GINT64_FORMAT, position); ical_comp = e_cal_component_get_icalcomponent (self->new_component); e_cal_util_component_set_x_property (ical_comp, ICAL_X_ENDEAVOUR_POSITION, value); } static const gchar* gtd_task_eds_get_title (GtdTask *task) { GtdTaskEds *self; g_return_val_if_fail (GTD_IS_TASK_EDS (task), NULL); self = GTD_TASK_EDS (task); return i_cal_component_get_summary (e_cal_component_get_icalcomponent (self->new_component)); } static void gtd_task_eds_set_title (GtdTask *task, const gchar *title) { ECalComponentText *new_summary; GtdTaskEds *self; g_return_if_fail (GTD_IS_TASK_EDS (task)); g_return_if_fail (g_utf8_validate (title, -1, NULL)); self = GTD_TASK_EDS (task); new_summary = e_cal_component_text_new (title, NULL); e_cal_component_set_summary (self->new_component, new_summary); e_cal_component_text_free (new_summary); } /* * GObject overrides */ static void gtd_task_eds_finalize (GObject *object) { GtdTaskEds *self = (GtdTaskEds *)object; g_clear_object (&self->component); g_clear_object (&self->new_component); G_OBJECT_CLASS (gtd_task_eds_parent_class)->finalize (object); } static void gtd_task_eds_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GtdTaskEds *self = GTD_TASK_EDS (object); switch (prop_id) { case PROP_COMPONENT: g_value_set_object (value, self->component); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void gtd_task_eds_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GtdTaskEds *self = GTD_TASK_EDS (object); switch (prop_id) { case PROP_COMPONENT: gtd_task_eds_set_component (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void gtd_task_eds_class_init (GtdTaskEdsClass *klass) { GtdObjectClass *gtd_object_class = GTD_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); GtdTaskClass *task_class = GTD_TASK_CLASS (klass); object_class->finalize = gtd_task_eds_finalize; object_class->get_property = gtd_task_eds_get_property; object_class->set_property = gtd_task_eds_set_property; task_class->get_complete = gtd_task_eds_get_complete; task_class->set_complete = gtd_task_eds_set_complete; task_class->get_creation_date = gtd_task_eds_get_creation_date; task_class->set_creation_date = gtd_task_eds_set_creation_date; task_class->get_completion_date = gtd_task_eds_get_completion_date; task_class->set_completion_date = gtd_task_eds_set_completion_date; task_class->get_description = gtd_task_eds_get_description; task_class->set_description = gtd_task_eds_set_description; task_class->get_due_date = gtd_task_eds_get_due_date; task_class->set_due_date = gtd_task_eds_set_due_date; task_class->get_important = gtd_task_eds_get_important; task_class->set_important = gtd_task_eds_set_important; task_class->get_position = gtd_task_eds_get_position; task_class->set_position = gtd_task_eds_set_position; task_class->get_title = gtd_task_eds_get_title; task_class->set_title = gtd_task_eds_set_title; gtd_object_class->get_uid = gtd_task_eds_get_uid; gtd_object_class->set_uid = gtd_task_eds_set_uid; properties[PROP_COMPONENT] = g_param_spec_object ("component", "Component", "Component", E_TYPE_CAL_COMPONENT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPS, properties); } static void gtd_task_eds_init (GtdTaskEds *self) { } GtdTask* gtd_task_eds_new (ECalComponent *component) { return g_object_new (GTD_TYPE_TASK_EDS, "component", component, NULL); } ECalComponent* gtd_task_eds_get_component (GtdTaskEds *self) { g_return_val_if_fail (GTD_IS_TASK_EDS (self), NULL); return self->new_component; } void gtd_task_eds_set_component (GtdTaskEds *self, ECalComponent *component) { GObject *object; g_return_if_fail (GTD_IS_TASK_EDS (self)); g_return_if_fail (E_IS_CAL_COMPONENT (component)); if (!g_set_object (&self->component, component)) return; object = G_OBJECT (self); g_clear_object (&self->new_component); self->new_component = e_cal_component_clone (component); setup_description (self); g_object_notify (object, "complete"); g_object_notify (object, "creation-date"); g_object_notify (object, "description"); g_object_notify (object, "due-date"); g_object_notify (object, "important"); g_object_notify (object, "position"); g_object_notify (object, "title"); g_object_notify_by_pspec (object, properties[PROP_COMPONENT]); } void gtd_task_eds_apply (GtdTaskEds *self) { g_return_if_fail (GTD_IS_TASK_EDS (self)); e_cal_component_commit_sequence (self->new_component); /* Make new_component the actual component */ gtd_task_eds_set_component (self, self->new_component); } void gtd_task_eds_revert (GtdTaskEds *self) { g_autoptr (ECalComponent) component = NULL; g_return_if_fail (GTD_IS_TASK_EDS (self)); component = e_cal_component_clone (self->component); gtd_task_eds_set_component (self, component); }