diff options
| author | Matthew Fennell <matthew@fennell.dev> | 2025-12-27 12:40:20 +0000 |
|---|---|---|
| committer | Matthew Fennell <matthew@fennell.dev> | 2025-12-27 12:40:20 +0000 |
| commit | 5d8e439bc597159e3c9f0a8b65c0ae869dead3a8 (patch) | |
| tree | ed28aefed8add0da1c55c08fdf80b23c4346e0dc /src/core/gtd-task.c | |
Import Upstream version 43.0upstream/latest
Diffstat (limited to 'src/core/gtd-task.c')
| -rw-r--r-- | src/core/gtd-task.c | 993 |
1 files changed, 993 insertions, 0 deletions
diff --git a/src/core/gtd-task.c b/src/core/gtd-task.c new file mode 100644 index 0000000..6951dec --- /dev/null +++ b/src/core/gtd-task.c @@ -0,0 +1,993 @@ +/* gtd-task.c + * + * Copyright (C) 2015-2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.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, 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 <http://www.gnu.org/licenses/>. + */ + +#define G_LOG_DOMAIN "GtdTask" + +#include "gtd-debug.h" +#include "gtd-task.h" +#include "gtd-task-list.h" + +#include <glib/gi18n.h> + +/** + * SECTION:gtd-task + * @short_description: a task + * @title:GtdTask + * @stability:Unstable + * @see_also:#GtdTaskList + * + * A #GtdTask is an object that represents a task. All #GtdTasks + * must be inside a #GtdTaskList. + */ + +typedef struct +{ + gchar *description; + GtdTaskList *list; + + GDateTime *creation_date; + GDateTime *completion_date; + GDateTime *due_date; + + gchar *title; + + gint32 priority; + gint64 position; + gboolean complete; + gboolean important; +} GtdTaskPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GtdTask, gtd_task, GTD_TYPE_OBJECT) + +enum +{ + PROP_0, + PROP_COMPLETE, + PROP_DESCRIPTION, + PROP_CREATION_DATE, + PROP_DUE_DATE, + PROP_IMPORTANT, + PROP_LIST, + PROP_POSITION, + PROP_TITLE, + LAST_PROP +}; + +static void +task_list_weak_notified (gpointer data, + GObject *where_the_object_was) +{ + GtdTask *task = GTD_TASK (data); + GtdTaskPrivate *priv = gtd_task_get_instance_private (task); + priv->list = NULL; +} + +/* + * GtdTask default implementations + */ + +static GDateTime* +gtd_task_real_get_completion_date (GtdTask *self) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + return priv->completion_date ? g_date_time_ref (priv->completion_date) : NULL; +} + +static void +gtd_task_real_set_completion_date (GtdTask *self, + GDateTime *dt) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + g_clear_pointer (&priv->completion_date, g_date_time_unref); + priv->completion_date = dt ? g_date_time_ref (dt) : NULL; +} + +static gboolean +gtd_task_real_get_complete (GtdTask *self) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + return priv->complete; +} + +static void +gtd_task_real_set_complete (GtdTask *self, + gboolean complete) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + GDateTime *dt; + + dt = complete ? g_date_time_new_now_local () : NULL; + gtd_task_real_set_completion_date (self, dt); + + priv->complete = complete; +} + +static GDateTime* +gtd_task_real_get_creation_date (GtdTask *self) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + return priv->creation_date ? g_date_time_ref (priv->creation_date) : NULL; +} + +static void +gtd_task_real_set_creation_date (GtdTask *self, + GDateTime *dt) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + g_clear_pointer (&priv->creation_date, g_date_time_unref); + priv->creation_date = dt ? g_date_time_ref (dt) : NULL; +} + +static const gchar* +gtd_task_real_get_description (GtdTask *self) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + return priv->description ? priv->description : ""; +} + +static void +gtd_task_real_set_description (GtdTask *self, + const gchar *description) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + g_clear_pointer (&priv->description, g_free); + priv->description = g_strdup (description); +} + +static GDateTime* +gtd_task_real_get_due_date (GtdTask *self) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + return priv->due_date ? g_date_time_ref (priv->due_date) : NULL; +} + +static void +gtd_task_real_set_due_date (GtdTask *self, + GDateTime *due_date) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + g_clear_pointer (&priv->due_date, g_date_time_unref); + + if (due_date) + priv->due_date = g_date_time_ref (due_date); +} + +static gboolean +gtd_task_real_get_important (GtdTask *self) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + return priv->important; +} + +static void +gtd_task_real_set_important (GtdTask *self, + gboolean important) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + if (priv->important == important) + return; + + priv->important = important; +} + +static gint64 +gtd_task_real_get_position (GtdTask *self) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + return priv->position; +} + +static void +gtd_task_real_set_position (GtdTask *self, + gint64 position) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + priv->position = position; +} + +static const gchar* +gtd_task_real_get_title (GtdTask *self) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + return priv->title; +} + +static void +gtd_task_real_set_title (GtdTask *self, + const gchar *title) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + g_clear_pointer (&priv->title, g_free); + priv->title = title ? g_strdup (title) : NULL; +} + + +/* + * GObject overrides + */ + +static void +gtd_task_finalize (GObject *object) +{ + GtdTask *self = (GtdTask*) object; + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + if (priv->list) + g_object_weak_unref (G_OBJECT (priv->list), task_list_weak_notified, self); + + priv->list = NULL; + g_free (priv->description); + + G_OBJECT_CLASS (gtd_task_parent_class)->finalize (object); +} + +static void +gtd_task_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtdTask *self = GTD_TASK (object); + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + GDateTime *date; + + switch (prop_id) + { + case PROP_COMPLETE: + g_value_set_boolean (value, gtd_task_get_complete (self)); + break; + + case PROP_CREATION_DATE: + g_value_set_boxed (value, gtd_task_get_creation_date (self)); + break; + + case PROP_DESCRIPTION: + g_value_set_string (value, gtd_task_get_description (self)); + break; + + case PROP_DUE_DATE: + date = gtd_task_get_due_date (self); + g_value_set_boxed (value, date); + g_clear_pointer (&date, g_date_time_unref); + break; + + case PROP_IMPORTANT: + g_value_set_boolean (value, gtd_task_get_important (self)); + break; + + case PROP_LIST: + g_value_set_object (value, priv->list); + break; + + case PROP_POSITION: + g_value_set_int64 (value, gtd_task_get_position (self)); + break; + + case PROP_TITLE: + g_value_set_string (value, gtd_task_get_title (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtd_task_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtdTask *self = GTD_TASK (object); + + switch (prop_id) + { + case PROP_COMPLETE: + gtd_task_set_complete (self, g_value_get_boolean (value)); + break; + + case PROP_CREATION_DATE: + gtd_task_set_creation_date (self, g_value_get_boxed (value)); + break; + + case PROP_DESCRIPTION: + gtd_task_set_description (self, g_value_get_string (value)); + break; + + case PROP_DUE_DATE: + gtd_task_set_due_date (self, g_value_get_boxed (value)); + break; + + case PROP_IMPORTANT: + gtd_task_set_important (self, g_value_get_boolean (value)); + break; + + case PROP_LIST: + gtd_task_set_list (self, g_value_get_object (value)); + break; + + case PROP_POSITION: + gtd_task_set_position (self, g_value_get_int64 (value)); + break; + + case PROP_TITLE: + gtd_task_set_title (self, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtd_task_class_init (GtdTaskClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + klass->get_complete = gtd_task_real_get_complete; + klass->set_complete = gtd_task_real_set_complete; + klass->get_creation_date = gtd_task_real_get_creation_date; + klass->set_creation_date = gtd_task_real_set_creation_date; + klass->get_completion_date = gtd_task_real_get_completion_date; + klass->set_completion_date = gtd_task_real_set_completion_date; + klass->get_description = gtd_task_real_get_description; + klass->set_description = gtd_task_real_set_description; + klass->get_due_date = gtd_task_real_get_due_date; + klass->set_due_date = gtd_task_real_set_due_date; + klass->get_important = gtd_task_real_get_important; + klass->set_important = gtd_task_real_set_important; + klass->get_position = gtd_task_real_get_position; + klass->set_position = gtd_task_real_set_position; + klass->get_title = gtd_task_real_get_title; + klass->set_title = gtd_task_real_set_title; + + object_class->finalize = gtd_task_finalize; + object_class->get_property = gtd_task_get_property; + object_class->set_property = gtd_task_set_property; + + /** + * GtdTask::complete: + * + * @TRUE if the task is marked as complete or @FALSE otherwise. Usually + * represented by a checkbox at user interfaces. + */ + g_object_class_install_property ( + object_class, + PROP_COMPLETE, + g_param_spec_boolean ("complete", + "Whether the task is completed or not", + "Whether the task is marked as completed by the user", + FALSE, + G_PARAM_READWRITE)); + + /** + * GtdTask::creation-date: + * + * The @GDateTime that represents the time in which the task was created. + */ + g_object_class_install_property ( + object_class, + PROP_CREATION_DATE, + g_param_spec_boxed ("creation-date", + "Creation date of the task", + "The day the task was created.", + G_TYPE_DATE_TIME, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GtdTask::description: + * + * Description of the task. + */ + g_object_class_install_property ( + object_class, + PROP_DESCRIPTION, + g_param_spec_string ("description", + "Description of the task", + "Optional string describing the task", + NULL, + G_PARAM_READWRITE)); + + /** + * GtdTask::due-date: + * + * The @GDateTime that represents the time in which the task should + * be completed before. + */ + g_object_class_install_property ( + object_class, + PROP_DUE_DATE, + g_param_spec_boxed ("due-date", + "End date of the task", + "The day the task is supposed to be completed", + G_TYPE_DATE_TIME, + G_PARAM_READWRITE)); + + /** + * GtdTask::important: + * + * @TRUE if the task is important, @FALSE otherwise. + */ + g_object_class_install_property ( + object_class, + PROP_IMPORTANT, + g_param_spec_boolean ("important", + "Whether the task is important or not", + "Whether the task is important or not", + FALSE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + + /** + * GtdTask::list: + * + * The @GtdTaskList that contains this task. + */ + g_object_class_install_property ( + object_class, + PROP_LIST, + g_param_spec_object ("list", + "List of the task", + "The list that owns this task", + GTD_TYPE_TASK_LIST, + G_PARAM_READWRITE)); + + /** + * GtdTask::position: + * + * Position of the task, -1 if not set. + */ + g_object_class_install_property ( + object_class, + PROP_POSITION, + g_param_spec_int64 ("position", + "Position of the task", + "The position of the task. -1 means no position, and tasks will be sorted alphabetically.", + -1, + G_MAXINT64, + 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GtdTask::title: + * + * The title of the task, usually the task name. + */ + g_object_class_install_property ( + object_class, + PROP_TITLE, + g_param_spec_string ("title", + "Title of the task", + "The title of the task", + NULL, + G_PARAM_READWRITE)); +} + +static void +gtd_task_init (GtdTask *self) +{ + GtdTaskPrivate *priv = gtd_task_get_instance_private (self); + + priv->position = -1; +} + +/** + * gtd_task_new: + * + * Creates a new #GtdTask + * + * Returns: (transfer full): a #GtdTask + */ +GtdTask * +gtd_task_new (void) +{ + return g_object_new (GTD_TYPE_TASK, NULL); +} + +/** + * gtd_task_get_complete: + * @self: a #GtdTask + * + * Retrieves whether the task is complete or not. + * + * Returns: %TRUE if the task is complete, %FALSE otherwise + */ +gboolean +gtd_task_get_complete (GtdTask *self) +{ + g_return_val_if_fail (GTD_IS_TASK (self), FALSE); + + return GTD_TASK_CLASS (G_OBJECT_GET_CLASS (self))->get_complete (self); +} + +/** + * gtd_task_set_complete: + * @self: a #GtdTask + * @complete: the new value + * + * Updates the complete state of @task. + */ +void +gtd_task_set_complete (GtdTask *task, + gboolean complete) +{ + g_return_if_fail (GTD_IS_TASK (task)); + + if (gtd_task_get_complete (task) == complete) + return; + + GTD_TASK_CLASS (G_OBJECT_GET_CLASS (task))->set_complete (task, complete); + + g_object_notify (G_OBJECT (task), "complete"); +} + +/** + * gtd_task_get_creation_date: + * @self: a #GtdTask + * + * Returns the #GDateTime that represents the task's creation date. + * The value is referenced for thread safety. Returns %NULL if + * no date is set. + * + * Returns: (transfer full): the internal #GDateTime referenced + * for thread safety, or %NULL. Unreference it after use. + */ +GDateTime* +gtd_task_get_creation_date (GtdTask *task) +{ + g_return_val_if_fail (GTD_IS_TASK (task), NULL); + + return GTD_TASK_CLASS (G_OBJECT_GET_CLASS (task))->get_creation_date (task); +} + +/** + * gtd_task_set_creation_date: + * @self: a #GtdTask + * + * Sets the creation date of @task. + */ +void +gtd_task_set_creation_date (GtdTask *task, + GDateTime *dt) +{ + g_return_if_fail (GTD_IS_TASK (task)); + + if (gtd_task_get_creation_date (task) == dt) + return; + + GTD_TASK_CLASS (G_OBJECT_GET_CLASS (task))->set_creation_date (task, dt); + + g_object_notify (G_OBJECT (task), "complete"); +} + +/** + * gtd_task_get_completion_date: + * @self: a #GtdTask + * + * Returns the #GDateTime that represents the task's completion date. + * Returns %NULL if no date is set. + * + * Returns: (transfer full)(nullable): the internal #GDateTime or %NULL. + * Unreference it after use. + */ +GDateTime* +gtd_task_get_completion_date (GtdTask *task) +{ + g_return_val_if_fail (GTD_IS_TASK (task), NULL); + + return GTD_TASK_CLASS (G_OBJECT_GET_CLASS (task))->get_completion_date (task); +} + +/** + * gtd_task_get_description: + * @self: a #GtdTask + * + * Retrieves the description of the task. + * + * Returns: (transfer none): the description of @task + */ +const gchar* +gtd_task_get_description (GtdTask *task) +{ + g_return_val_if_fail (GTD_IS_TASK (task), NULL); + + return GTD_TASK_CLASS (G_OBJECT_GET_CLASS (task))->get_description (task); +} + +/** + * gtd_task_set_description: + * @self: a #GtdTask + * @description: (nullable): the new description, or %NULL + * + * Updates the description of @task. The string is not stripped off of + * spaces to preserve user data. + */ +void +gtd_task_set_description (GtdTask *task, + const gchar *description) +{ + GtdTaskPrivate *priv; + + g_assert (GTD_IS_TASK (task)); + g_assert (g_utf8_validate (description, -1, NULL)); + + priv = gtd_task_get_instance_private (task); + + if (g_strcmp0 (priv->description, description) == 0) + return; + + GTD_TASK_CLASS (G_OBJECT_GET_CLASS (task))->set_description (task, description); + + g_object_notify (G_OBJECT (task), "description"); +} + +/** + * gtd_task_get_due_date: + * @self: a #GtdTask + * + * Returns the #GDateTime that represents the task's due date. + * The value is referenced for thread safety. Returns %NULL if + * no date is set. + * + * Returns: (transfer full) (nullable): the internal #GDateTime referenced + * for thread safety, or %NULL. Unreference it after use. + */ +GDateTime* +gtd_task_get_due_date (GtdTask *task) +{ + g_return_val_if_fail (GTD_IS_TASK (task), NULL); + + return GTD_TASK_CLASS (G_OBJECT_GET_CLASS (task))->get_due_date (task); +} + +/** + * gtd_task_set_due_date: + * @self: a #GtdTask + * @dt: (nullable): a #GDateTime + * + * Updates the internal @GtdTask::due-date property. + */ +void +gtd_task_set_due_date (GtdTask *task, + GDateTime *dt) +{ + g_autoptr (GDateTime) current_dt = NULL; + + g_assert (GTD_IS_TASK (task)); + + current_dt = gtd_task_get_due_date (task); + + /* Don't do anything if the date is equal */ + if (current_dt == dt || (current_dt && dt && g_date_time_equal (current_dt, dt))) + return; + + GTD_TASK_CLASS (G_OBJECT_GET_CLASS (task))->set_due_date (task, dt); + + g_object_notify (G_OBJECT (task), "due-date"); +} + +/** + * gtd_task_get_important: + * @self: a #GtdTask + * + * Retrieves whether @self is @important or not. + * + * Returns: %TRUE if @self is important, %FALSE otherwise + */ +gboolean +gtd_task_get_important (GtdTask *self) +{ + g_return_val_if_fail (GTD_IS_TASK (self), FALSE); + + return GTD_TASK_GET_CLASS (self)->get_important (self); +} + +/** + * gtd_task_set_important: + * @self: a #GtdTask + * @important: whether @self is important or not + * + * Sets whether @self is @important or not. + */ +void +gtd_task_set_important (GtdTask *self, + gboolean important) +{ + g_return_if_fail (GTD_IS_TASK (self)); + + important = !!important; + + GTD_TASK_GET_CLASS (self)->set_important (self, important); + g_object_notify (G_OBJECT (self), "important"); +} + +/** + * gtd_task_get_list: + * + * Returns a weak reference to the #GtdTaskList that + * owns the given @task. + * + * Returns: (transfer none): a weak reference to the + * #GtdTaskList that owns @task. Do not free after + * usage. + */ +GtdTaskList* +gtd_task_get_list (GtdTask *task) +{ + GtdTaskPrivate *priv; + + g_return_val_if_fail (GTD_IS_TASK (task), NULL); + + priv = gtd_task_get_instance_private (task); + + return priv->list; +} + +/** + * gtd_task_set_list: + * @self: a #GtdTask + * @list: (nullable): a #GtdTaskList + * + * Sets the parent #GtdTaskList of @task. + */ +void +gtd_task_set_list (GtdTask *task, + GtdTaskList *list) +{ + GtdTaskPrivate *priv; + + g_assert (GTD_IS_TASK (task)); + g_assert (GTD_IS_TASK_LIST (list)); + + priv = gtd_task_get_instance_private (task); + + if (priv->list == list) + return; + + if (priv->list) + g_object_weak_unref (G_OBJECT (priv->list), task_list_weak_notified, task); + + priv->list = list; + g_object_weak_ref (G_OBJECT (priv->list), task_list_weak_notified, task); + g_object_notify (G_OBJECT (task), "list"); +} + +/** + * gtd_task_get_position: + * @self: a #GtdTask + * + * Returns the position of @task inside the parent #GtdTaskList, + * or -1 if not set. + * + * Returns: the position of the task, or -1 + */ +gint64 +gtd_task_get_position (GtdTask *self) +{ + g_return_val_if_fail (GTD_IS_TASK (self), -1); + + return GTD_TASK_CLASS (G_OBJECT_GET_CLASS (self))->get_position (self); +} + +/** + * gtd_task_set_position: + * @self: a #GtdTask + * @position: the priority of @task, or -1 + * + * Sets the @task position inside the parent #GtdTaskList. It + * is up to the interface to handle two or more #GtdTask with + * the same position value. + */ +void +gtd_task_set_position (GtdTask *self, + gint64 position) +{ + g_return_if_fail (GTD_IS_TASK (self)); + + if (gtd_task_get_position (self) == position) + return; + + GTD_TASK_CLASS (G_OBJECT_GET_CLASS (self))->set_position (self, position); + + g_object_notify (G_OBJECT (self), "position"); +} + +/** + * gtd_task_get_title: + * @self: a #GtdTask + * + * Retrieves the title of the task, or %NULL. + * + * Returns: (transfer none): the title of @task, or %NULL + */ +const gchar* +gtd_task_get_title (GtdTask *task) +{ + const gchar *title; + + g_return_val_if_fail (GTD_IS_TASK (task), NULL); + + title = GTD_TASK_CLASS (G_OBJECT_GET_CLASS (task))->get_title (task); + + return title ? title : ""; +} + +/** + * gtd_task_set_title: + * @self: a #GtdTask + * @title: (nullable): the new title, or %NULL + * + * Updates the title of @task. The string is stripped off of + * leading spaces. + */ +void +gtd_task_set_title (GtdTask *task, + const gchar *title) +{ + const gchar *current_title; + + g_return_if_fail (GTD_IS_TASK (task)); + g_return_if_fail (g_utf8_validate (title, -1, NULL)); + + current_title = gtd_task_get_title (task); + + if (g_strcmp0 (current_title, title) == 0) + return; + + GTD_TASK_CLASS (G_OBJECT_GET_CLASS (task))->set_title (task, title); + + g_object_notify (G_OBJECT (task), "title"); +} + +/** + * gtd_task_compare: + * @t1: (nullable): a #GtdTask + * @t2: (nullable): a #GtdTask + * + * Compare @t1 and @t2. + * + * Returns: %-1 if @t1 comes before @t2, %1 for the opposite, %0 if they're equal + */ +gint +gtd_task_compare (GtdTask *t1, + GtdTask *t2) +{ + GDateTime *dt1; + GDateTime *dt2; + gchar *txt1; + gchar *txt2; + gint retval; + + if (!t1 && !t2) + return 0; + if (!t1) + return 1; + if (!t2) + return -1; + + /* + * The custom position overrides any comparison we can make. To keep compatibility, + * for now, we only compare by position if both tasks have a custom position set. + */ + if (gtd_task_get_position (t1) != -1 && gtd_task_get_position (t2) != -1) + { + retval = gtd_task_get_position (t1) - gtd_task_get_position (t2); + + if (retval != 0) + return retval; + } + + /* Compare by due date */ + dt1 = gtd_task_get_due_date (t1); + dt2 = gtd_task_get_due_date (t2); + + if (!dt1 && !dt2) + retval = 0; + else if (!dt1) + retval = 1; + else if (!dt2) + retval = -1; + else + retval = g_date_time_compare (dt1, dt2); + + if (dt1) + g_date_time_unref (dt1); + if (dt2) + g_date_time_unref (dt2); + + if (retval != 0) + return retval; + + /* Compare by creation date */ + dt1 = gtd_task_get_creation_date (t1); + dt2 = gtd_task_get_creation_date (t2); + + if (!dt1 && !dt2) + retval = 0; + else if (!dt1) + retval = 1; + else if (!dt2) + retval = -1; + else + retval = g_date_time_compare (dt1, dt2); + + g_clear_pointer (&dt1, g_date_time_unref); + g_clear_pointer (&dt2, g_date_time_unref); + + if (retval != 0) + return retval; + + /* If they're equal up to now, compare by title */ + txt1 = txt2 = NULL; + + txt1 = g_utf8_casefold (gtd_task_get_title (t1), -1); + txt2 = g_utf8_casefold (gtd_task_get_title (t2), -1); + + retval = g_strcmp0 (txt1, txt2); + + g_free (txt1); + g_free (txt2); + + return retval; +} + +/** + * gtd_task_get_provider: + * @self: a #GtdTaskList + * + * Utility function to retrieve the data provider that backs this + * task. Notice that this is exactly the same as writing: + * + * |[<!-- language="C" --> + * GtdTaskList *list; + * GtdProvider *provider; + * + * list = gtd_task_get_list (task); + * provider = gtd_task_list_get_provider (list); + * ]| + * + * Returns: (transfer none)(nullable): the #GtdProvider of this task's list. + */ +GtdProvider* +gtd_task_get_provider (GtdTask *self) +{ + GtdTaskPrivate *priv; + + g_return_val_if_fail (GTD_IS_TASK (self), NULL); + + priv = gtd_task_get_instance_private (self); + + if (priv->list) + return gtd_task_list_get_provider (priv->list); + + return NULL; +} |
