evolution-3.6.4/calendar/gui/e-cal-model-tasks.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-cal-model-tasks.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-cal-model-tasks.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
   1 /*
   2  * Evolution calendar - Data model for ETable
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) version 3.
   8  *
   9  * This program is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  16  *
  17  *
  18  * Authors:
  19  *		Rodrigo Moya <rodrigo@ximian.com>
  20  *
  21  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  22  *
  23  */
  24 
  25 #ifdef HAVE_CONFIG_H
  26 #include <config.h>
  27 #endif
  28 
  29 #include <math.h>
  30 #include <string.h>
  31 #include <gtk/gtk.h>
  32 #include <glib/gi18n.h>
  33 
  34 #include "calendar-config.h"
  35 #include "e-cal-model-tasks.h"
  36 #include "e-cell-date-edit-text.h"
  37 #include "misc.h"
  38 
  39 #define E_CAL_MODEL_TASKS_GET_PRIVATE(obj) \
  40 	(G_TYPE_INSTANCE_GET_PRIVATE \
  41 	((obj), E_TYPE_CAL_MODEL_TASKS, ECalModelTasksPrivate))
  42 
  43 struct _ECalModelTasksPrivate {
  44 	gboolean highlight_due_today;
  45 	gchar *color_due_today;
  46 	gboolean highlight_overdue;
  47 	gchar *color_overdue;
  48 };
  49 
  50 static gint ecmt_column_count (ETableModel *etm);
  51 static gpointer ecmt_value_at (ETableModel *etm, gint col, gint row);
  52 static void ecmt_set_value_at (ETableModel *etm, gint col, gint row, gconstpointer value);
  53 static gboolean ecmt_is_cell_editable (ETableModel *etm, gint col, gint row);
  54 static gpointer ecmt_duplicate_value (ETableModel *etm, gint col, gconstpointer value);
  55 static void ecmt_free_value (ETableModel *etm, gint col, gpointer value);
  56 static gpointer ecmt_initialize_value (ETableModel *etm, gint col);
  57 static gboolean ecmt_value_is_empty (ETableModel *etm, gint col, gconstpointer value);
  58 static gchar *ecmt_value_to_string (ETableModel *etm, gint col, gconstpointer value);
  59 
  60 static const gchar *ecmt_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data);
  61 static void ecmt_fill_component_from_model (ECalModel *model, ECalModelComponent *comp_data,
  62 					    ETableModel *source_model, gint row);
  63 static void commit_component_changes (ECalModelComponent *comp_data);
  64 
  65 G_DEFINE_TYPE (ECalModelTasks, e_cal_model_tasks, E_TYPE_CAL_MODEL)
  66 
  67 enum {
  68 	PROP_0,
  69 	PROP_HIGHLIGHT_DUE_TODAY,
  70 	PROP_COLOR_DUE_TODAY,
  71 	PROP_HIGHLIGHT_OVERDUE,
  72 	PROP_COLOR_OVERDUE
  73 };
  74 
  75 static void
  76 cal_model_tasks_set_property (GObject *object,
  77                               guint property_id,
  78                               const GValue *value,
  79                               GParamSpec *pspec)
  80 {
  81 	switch (property_id) {
  82 		case PROP_HIGHLIGHT_DUE_TODAY:
  83 			e_cal_model_tasks_set_highlight_due_today (
  84 				E_CAL_MODEL_TASKS (object),
  85 				g_value_get_boolean (value));
  86 			return;
  87 
  88 		case PROP_COLOR_DUE_TODAY:
  89 			e_cal_model_tasks_set_color_due_today (
  90 				E_CAL_MODEL_TASKS (object),
  91 				g_value_get_string (value));
  92 			return;
  93 
  94 		case PROP_HIGHLIGHT_OVERDUE:
  95 			e_cal_model_tasks_set_highlight_overdue (
  96 				E_CAL_MODEL_TASKS (object),
  97 				g_value_get_boolean (value));
  98 			return;
  99 
 100 		case PROP_COLOR_OVERDUE:
 101 			e_cal_model_tasks_set_color_overdue (
 102 				E_CAL_MODEL_TASKS (object),
 103 				g_value_get_string (value));
 104 			return;
 105 	}
 106 
 107 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 108 }
 109 
 110 static void
 111 cal_model_tasks_get_property (GObject *object,
 112                               guint property_id,
 113                               GValue *value,
 114                               GParamSpec *pspec)
 115 {
 116 	switch (property_id) {
 117 		case PROP_HIGHLIGHT_DUE_TODAY:
 118 			g_value_set_boolean (
 119 				value,
 120 				e_cal_model_tasks_get_highlight_due_today (
 121 				E_CAL_MODEL_TASKS (object)));
 122 			return;
 123 
 124 		case PROP_COLOR_DUE_TODAY:
 125 			g_value_set_string (
 126 				value,
 127 				e_cal_model_tasks_get_color_due_today (
 128 				E_CAL_MODEL_TASKS (object)));
 129 			return;
 130 
 131 		case PROP_HIGHLIGHT_OVERDUE:
 132 			g_value_set_boolean (
 133 				value,
 134 				e_cal_model_tasks_get_highlight_overdue (
 135 				E_CAL_MODEL_TASKS (object)));
 136 			return;
 137 
 138 		case PROP_COLOR_OVERDUE:
 139 			g_value_set_string (
 140 				value,
 141 				e_cal_model_tasks_get_color_overdue (
 142 				E_CAL_MODEL_TASKS (object)));
 143 			return;
 144 	}
 145 
 146 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 147 }
 148 
 149 static void
 150 cal_model_tasks_finalize (GObject *object)
 151 {
 152 	ECalModelTasksPrivate *priv;
 153 
 154 	priv = E_CAL_MODEL_TASKS_GET_PRIVATE (object);
 155 
 156 	g_free (priv->color_due_today);
 157 	g_free (priv->color_overdue);
 158 
 159 	/* Chain up to parent's finalize() method. */
 160 	G_OBJECT_CLASS (e_cal_model_tasks_parent_class)->finalize (object);
 161 }
 162 
 163 static void
 164 e_cal_model_tasks_class_init (ECalModelTasksClass *class)
 165 {
 166 	GObjectClass *object_class;
 167 	ETableModelClass *table_model_class;
 168 	ECalModelClass *cal_model_class;
 169 
 170 	g_type_class_add_private (class, sizeof (ECalModelTasksPrivate));
 171 
 172 	object_class = G_OBJECT_CLASS (class);
 173 	object_class->set_property = cal_model_tasks_set_property;
 174 	object_class->get_property = cal_model_tasks_get_property;
 175 	object_class->finalize = cal_model_tasks_finalize;
 176 
 177 	table_model_class = E_TABLE_MODEL_CLASS (class);
 178 	table_model_class->column_count = ecmt_column_count;
 179 	table_model_class->value_at = ecmt_value_at;
 180 	table_model_class->set_value_at = ecmt_set_value_at;
 181 	table_model_class->is_cell_editable = ecmt_is_cell_editable;
 182 	table_model_class->duplicate_value = ecmt_duplicate_value;
 183 	table_model_class->free_value = ecmt_free_value;
 184 	table_model_class->initialize_value = ecmt_initialize_value;
 185 	table_model_class->value_is_empty = ecmt_value_is_empty;
 186 	table_model_class->value_to_string = ecmt_value_to_string;
 187 
 188 	cal_model_class = E_CAL_MODEL_CLASS (class);
 189 	cal_model_class->get_color_for_component = ecmt_get_color_for_component;
 190 	cal_model_class->fill_component_from_model = ecmt_fill_component_from_model;
 191 
 192 	g_object_class_install_property (
 193 		object_class,
 194 		PROP_HIGHLIGHT_DUE_TODAY,
 195 		g_param_spec_boolean (
 196 			"highlight-due-today",
 197 			"Highlight Due Today",
 198 			NULL,
 199 			TRUE,
 200 			G_PARAM_READWRITE));
 201 
 202 	g_object_class_install_property (
 203 		object_class,
 204 		PROP_COLOR_DUE_TODAY,
 205 		g_param_spec_string (
 206 			"color-due-today",
 207 			"Color Due Today",
 208 			NULL,
 209 			"#1e90ff",
 210 			G_PARAM_READWRITE));
 211 
 212 	g_object_class_install_property (
 213 		object_class,
 214 		PROP_HIGHLIGHT_OVERDUE,
 215 		g_param_spec_boolean (
 216 			"highlight-overdue",
 217 			"Highlight Overdue",
 218 			NULL,
 219 			TRUE,
 220 			G_PARAM_READWRITE));
 221 
 222 	g_object_class_install_property (
 223 		object_class,
 224 		PROP_COLOR_OVERDUE,
 225 		g_param_spec_string (
 226 			"color-overdue",
 227 			"Color Overdue",
 228 			NULL,
 229 			"#ff0000",
 230 			G_PARAM_READWRITE));
 231 }
 232 
 233 static void
 234 e_cal_model_tasks_init (ECalModelTasks *model)
 235 {
 236 	model->priv = E_CAL_MODEL_TASKS_GET_PRIVATE (model);
 237 
 238 	model->priv->highlight_due_today = TRUE;
 239 	model->priv->highlight_overdue = TRUE;
 240 
 241 	e_cal_model_set_component_kind (
 242 		E_CAL_MODEL (model), ICAL_VTODO_COMPONENT);
 243 }
 244 
 245 /* ETableModel methods */
 246 static gint
 247 ecmt_column_count (ETableModel *etm)
 248 {
 249 	return E_CAL_MODEL_TASKS_FIELD_LAST;
 250 }
 251 
 252 /* This makes sure a task is marked as complete.
 253  * It makes sure the "Date Completed" property is set. If the completed_date
 254  * is not -1, then that is used, otherwise if the "Date Completed" property
 255  * is not already set it is set to the current time.
 256  * It makes sure the percent is set to 100, and that the status is "Completed".
 257  * Note that this doesn't update the component on the server. */
 258 static void
 259 ensure_task_complete (ECalModelComponent *comp_data,
 260                       time_t completed_date)
 261 {
 262 	icalproperty *prop;
 263 	gboolean set_completed = TRUE;
 264 
 265 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
 266 
 267 	/* Date Completed. */
 268 	if (completed_date == -1) {
 269 		if (prop)
 270 			set_completed = FALSE;
 271 		else
 272 			completed_date = time (NULL);
 273 	}
 274 
 275 	if (set_completed) {
 276 		icaltimezone *utc_zone;
 277 		struct icaltimetype new_completed;
 278 
 279 		/* COMPLETED is stored in UTC. */
 280 		utc_zone = icaltimezone_get_utc_timezone ();
 281 		new_completed = icaltime_from_timet_with_zone (
 282 			completed_date,
 283 			FALSE,
 284 			utc_zone);
 285 		if (prop)
 286 			icalproperty_set_completed (prop, new_completed);
 287 		else {
 288 			prop = icalproperty_new_completed (new_completed);
 289 			icalcomponent_add_property (comp_data->icalcomp, prop);
 290 		}
 291 	}
 292 
 293 	/* Percent. */
 294 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY);
 295 	if (!prop)
 296 		icalcomponent_add_property (comp_data->icalcomp, icalproperty_new_percentcomplete (100));
 297 	else
 298 		icalproperty_set_percentcomplete (prop, 100);
 299 
 300 	/* Status. */
 301 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY);
 302 	if (prop)
 303 		icalproperty_set_status (prop, ICAL_STATUS_COMPLETED);
 304 	else
 305 		icalcomponent_add_property (comp_data->icalcomp, icalproperty_new_status (ICAL_STATUS_COMPLETED));
 306 }
 307 
 308 static void
 309 ensure_task_partially_complete (ECalModelComponent *comp_data)
 310 {
 311 	icalproperty *prop;
 312 
 313 	/* Date Completed. */
 314 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
 315 	if (prop) {
 316 		icalcomponent_remove_property (comp_data->icalcomp, prop);
 317 		icalproperty_free (prop);
 318 	}
 319 
 320 	/* Percent. */
 321 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY);
 322 	if (!prop)
 323 		icalcomponent_add_property (comp_data->icalcomp, icalproperty_new_percentcomplete (50));
 324 	else if (icalproperty_get_percentcomplete (prop) == 0 || icalproperty_get_percentcomplete (prop) == 100)
 325 		icalproperty_set_percentcomplete (prop, 50);
 326 
 327 	/* Status. */
 328 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY);
 329 	if (prop)
 330 		icalproperty_set_status (prop, ICAL_STATUS_INPROCESS);
 331 	else
 332 		icalcomponent_add_property (comp_data->icalcomp, icalproperty_new_status (ICAL_STATUS_INPROCESS));
 333 }
 334 
 335 /* This makes sure a task is marked as incomplete. It clears the
 336  * "Date Completed" property. If the percent is set to 100 it removes it,
 337  * and if the status is "Completed" it sets it to "Needs Action".
 338  * Note that this doesn't update the component on the client. */
 339 static void
 340 ensure_task_not_complete (ECalModelComponent *comp_data)
 341 {
 342 	icalproperty *prop;
 343 
 344 	/* Date Completed. */
 345 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
 346 	if (prop) {
 347 		icalcomponent_remove_property (comp_data->icalcomp, prop);
 348 		icalproperty_free (prop);
 349 	}
 350 
 351 	/* Percent. */
 352 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY);
 353 	if (prop) {
 354 		icalcomponent_remove_property (comp_data->icalcomp, prop);
 355 		icalproperty_free (prop);
 356 	}
 357 
 358 	/* Status. */
 359 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY);
 360 	if (prop)
 361 		icalproperty_set_status (prop, ICAL_STATUS_NEEDSACTION);
 362 }
 363 
 364 static ECellDateEditValue *
 365 get_completed (ECalModelComponent *comp_data)
 366 {
 367 	struct icaltimetype tt_completed;
 368 
 369 	if (!comp_data->completed) {
 370 		icaltimezone *zone;
 371 		icalproperty *prop;
 372 
 373 		prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
 374 		if (!prop)
 375 			return NULL;
 376 
 377 		tt_completed = icalproperty_get_completed (prop);
 378 		if (!icaltime_is_valid_time (tt_completed) || icaltime_is_null_time (tt_completed))
 379 			return NULL;
 380 
 381 		comp_data->completed = g_new0 (ECellDateEditValue, 1);
 382 		comp_data->completed->tt = tt_completed;
 383 
 384 		if (icaltime_get_tzid (tt_completed)
 385 		    && e_cal_client_get_timezone_sync (comp_data->client, icaltime_get_tzid (tt_completed), &zone, NULL, NULL))
 386 			comp_data->completed->zone = zone;
 387 		else
 388 			comp_data->completed->zone = NULL;
 389 	}
 390 
 391 	return comp_data->completed;
 392 }
 393 
 394 static ECellDateEditValue *
 395 get_due (ECalModelComponent *comp_data)
 396 {
 397 	struct icaltimetype tt_due;
 398 
 399 	if (!comp_data->due) {
 400 		icaltimezone *zone;
 401 		icalproperty *prop;
 402 
 403 		prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DUE_PROPERTY);
 404 		if (!prop)
 405 			return NULL;
 406 
 407 		tt_due = icalproperty_get_due (prop);
 408 		if (!icaltime_is_valid_time (tt_due) || icaltime_is_null_time (tt_due))
 409 			return NULL;
 410 
 411 		comp_data->due = g_new0 (ECellDateEditValue, 1);
 412 		comp_data->due->tt = tt_due;
 413 
 414 		if (icaltime_get_tzid (tt_due)
 415 		    && e_cal_client_get_timezone_sync (comp_data->client, icaltime_get_tzid (tt_due), &zone, NULL, NULL))
 416 			comp_data->due->zone = zone;
 417 		else
 418 			comp_data->due->zone = NULL;
 419 	}
 420 
 421 	return comp_data->due;
 422 }
 423 
 424 static gpointer
 425 get_geo (ECalModelComponent *comp_data)
 426 {
 427 	icalproperty *prop;
 428 	struct icalgeotype geo;
 429 	static gchar buf[32];
 430 
 431 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_GEO_PROPERTY);
 432 	if (prop) {
 433 		geo = icalproperty_get_geo (prop);
 434 		g_snprintf (
 435 			buf, sizeof (buf), "%g %s, %g %s",
 436 			fabs (geo.lat),
 437 			geo.lat >= 0.0 ? "N" : "S",
 438 			fabs (geo.lon),
 439 			geo.lon >= 0.0 ? "E" : "W");
 440 		return buf;
 441 	}
 442 
 443 	return (gpointer) "";
 444 }
 445 
 446 static gint
 447 get_percent (ECalModelComponent *comp_data)
 448 {
 449 	icalproperty *prop;
 450 
 451 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY);
 452 	if (prop)
 453 		return icalproperty_get_percentcomplete (prop);
 454 
 455 	return 0;
 456 }
 457 
 458 static gpointer
 459 get_priority (ECalModelComponent *comp_data)
 460 {
 461 	icalproperty *prop;
 462 
 463 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PRIORITY_PROPERTY);
 464 	if (prop)
 465 		return (gpointer) e_cal_util_priority_to_string (icalproperty_get_priority (prop));
 466 
 467 	return (gpointer) "";
 468 }
 469 
 470 static gboolean
 471 is_status_canceled (ECalModelComponent *comp_data)
 472 {
 473 	icalproperty *prop;
 474 
 475 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY);
 476 
 477 	return prop && icalproperty_get_status (prop) == ICAL_STATUS_CANCELLED;
 478 }
 479 
 480 static gpointer
 481 get_status (ECalModelComponent *comp_data)
 482 {
 483 	icalproperty *prop;
 484 
 485 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY);
 486 	if (prop) {
 487 		switch (icalproperty_get_status (prop)) {
 488 		case ICAL_STATUS_NONE:
 489 			return (gpointer) "";
 490 		case ICAL_STATUS_NEEDSACTION:
 491 			return (gpointer) _("Not Started");
 492 		case ICAL_STATUS_INPROCESS:
 493 			return (gpointer) _("In Progress");
 494 		case ICAL_STATUS_COMPLETED:
 495 			return (gpointer) _("Completed");
 496 		case ICAL_STATUS_CANCELLED:
 497 			return (gpointer) _("Canceled");
 498 		default:
 499 			return (gpointer) "";
 500 		}
 501 	}
 502 
 503 	return (gpointer) "";
 504 }
 505 
 506 static gpointer
 507 get_url (ECalModelComponent *comp_data)
 508 {
 509 	icalproperty *prop;
 510 
 511 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_URL_PROPERTY);
 512 	if (prop)
 513 		return (gpointer) icalproperty_get_url (prop);
 514 
 515 	return (gpointer) "";
 516 }
 517 
 518 static gboolean
 519 is_complete (ECalModelComponent *comp_data)
 520 {
 521 	icalproperty *prop;
 522 
 523 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
 524 	if (prop)
 525 		return TRUE;
 526 
 527 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY);
 528 	if (prop && icalproperty_get_percentcomplete (prop) == 100)
 529 		return TRUE;
 530 
 531 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY);
 532 	if (prop && icalproperty_get_status (prop) == ICAL_STATUS_COMPLETED)
 533 		return TRUE;
 534 
 535 	return FALSE;
 536 }
 537 
 538 typedef enum {
 539 	E_CAL_MODEL_TASKS_DUE_NEVER,
 540 	E_CAL_MODEL_TASKS_DUE_FUTURE,
 541 	E_CAL_MODEL_TASKS_DUE_TODAY,
 542 	E_CAL_MODEL_TASKS_DUE_OVERDUE,
 543 	E_CAL_MODEL_TASKS_DUE_COMPLETE
 544 } ECalModelTasksDueStatus;
 545 
 546 static ECalModelTasksDueStatus
 547 get_due_status (ECalModelTasks *model,
 548                 ECalModelComponent *comp_data)
 549 {
 550 	icalproperty *prop;
 551 
 552 	/* First, do we have a due date? */
 553 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DUE_PROPERTY);
 554 	if (!prop)
 555 		return E_CAL_MODEL_TASKS_DUE_NEVER;
 556 	else {
 557 		struct icaltimetype now_tt, due_tt;
 558 		icaltimezone *zone;
 559 
 560 		/* Second, is it already completed? */
 561 		if (is_complete (comp_data))
 562 			return E_CAL_MODEL_TASKS_DUE_COMPLETE;
 563 
 564 		/* Third, are we overdue as of right now? */
 565 		due_tt = icalproperty_get_due (prop);
 566 		if (due_tt.is_date) {
 567 			gint cmp;
 568 
 569 			now_tt = icaltime_current_time_with_zone (e_cal_model_get_timezone (E_CAL_MODEL (model)));
 570 			cmp = icaltime_compare_date_only (due_tt, now_tt);
 571 
 572 			if (cmp < 0)
 573 				return E_CAL_MODEL_TASKS_DUE_OVERDUE;
 574 			else if (cmp == 0)
 575 				return E_CAL_MODEL_TASKS_DUE_TODAY;
 576 			else
 577 				return E_CAL_MODEL_TASKS_DUE_FUTURE;
 578 		} else {
 579 			icalparameter *param;
 580 			const gchar *tzid;
 581 
 582 			if (!(param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER)))
 583 				return E_CAL_MODEL_TASKS_DUE_FUTURE;
 584 
 585 			/* Get the current time in the same timezone as the DUE date.*/
 586 			tzid = icalparameter_get_tzid (param);
 587 			if (!e_cal_client_get_timezone_sync (comp_data->client, tzid, &zone, NULL, NULL))
 588 				return E_CAL_MODEL_TASKS_DUE_FUTURE;
 589 
 590 			now_tt = icaltime_current_time_with_zone (zone);
 591 
 592 			if (icaltime_compare (due_tt, now_tt) <= 0)
 593 				return E_CAL_MODEL_TASKS_DUE_OVERDUE;
 594 			else
 595 				if (icaltime_compare_date_only (due_tt, now_tt) == 0)
 596 					return E_CAL_MODEL_TASKS_DUE_TODAY;
 597 				else
 598 					return E_CAL_MODEL_TASKS_DUE_FUTURE;
 599 		}
 600 	}
 601 }
 602 
 603 static gboolean
 604 is_overdue (ECalModelTasks *model,
 605             ECalModelComponent *comp_data)
 606 {
 607 	switch (get_due_status (model, comp_data)) {
 608 	case E_CAL_MODEL_TASKS_DUE_NEVER:
 609 	case E_CAL_MODEL_TASKS_DUE_FUTURE:
 610 	case E_CAL_MODEL_TASKS_DUE_COMPLETE:
 611 		return FALSE;
 612 	case E_CAL_MODEL_TASKS_DUE_TODAY:
 613 	case E_CAL_MODEL_TASKS_DUE_OVERDUE:
 614 		return TRUE;
 615 	}
 616 
 617 	return FALSE;
 618 }
 619 
 620 static gpointer
 621 ecmt_value_at (ETableModel *etm,
 622                gint col,
 623                gint row)
 624 {
 625 	ECalModelComponent *comp_data;
 626 	ECalModelTasks *model = (ECalModelTasks *) etm;
 627 
 628 	g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), NULL);
 629 
 630 	g_return_val_if_fail (col >= 0 && (col < E_CAL_MODEL_TASKS_FIELD_LAST || col == E_CAL_MODEL_TASKS_FIELD_STRIKEOUT), NULL);
 631 	g_return_val_if_fail (row >= 0 && row < e_table_model_row_count (etm), NULL);
 632 
 633 	if (col < E_CAL_MODEL_FIELD_LAST)
 634 		return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->value_at (etm, col, row);
 635 
 636 	comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
 637 	if (!comp_data)
 638 		return (gpointer) "";
 639 
 640 	switch (col) {
 641 	case E_CAL_MODEL_TASKS_FIELD_COMPLETED :
 642 		return get_completed (comp_data);
 643 	case E_CAL_MODEL_TASKS_FIELD_STRIKEOUT :
 644 		return GINT_TO_POINTER (is_status_canceled (comp_data) || is_complete (comp_data));
 645 	case E_CAL_MODEL_TASKS_FIELD_COMPLETE :
 646 		return GINT_TO_POINTER (is_complete (comp_data));
 647 	case E_CAL_MODEL_TASKS_FIELD_DUE :
 648 		return get_due (comp_data);
 649 	case E_CAL_MODEL_TASKS_FIELD_GEO :
 650 		return get_geo (comp_data);
 651 	case E_CAL_MODEL_TASKS_FIELD_OVERDUE :
 652 		return GINT_TO_POINTER (is_overdue (model, comp_data));
 653 	case E_CAL_MODEL_TASKS_FIELD_PERCENT :
 654 		return GINT_TO_POINTER (get_percent (comp_data));
 655 	case E_CAL_MODEL_TASKS_FIELD_PRIORITY :
 656 		return get_priority (comp_data);
 657 	case E_CAL_MODEL_TASKS_FIELD_STATUS :
 658 		return get_status (comp_data);
 659 	case E_CAL_MODEL_TASKS_FIELD_URL :
 660 		return get_url (comp_data);
 661 	}
 662 
 663 	return (gpointer) "";
 664 }
 665 
 666 static void
 667 set_completed (ECalModelTasks *model,
 668                ECalModelComponent *comp_data,
 669                gconstpointer value)
 670 {
 671 	ECellDateEditValue *dv = (ECellDateEditValue *) value;
 672 
 673 	if (!dv)
 674 		ensure_task_not_complete (comp_data);
 675 	else {
 676 		time_t t;
 677 
 678 		if (dv->tt.is_date) {
 679 			/* if it's a date, it will be floating,
 680 			 * but completed needs a date time value */
 681 			dv->tt.is_date = FALSE;
 682 			t = icaltime_as_timet_with_zone (dv->tt, e_cal_model_get_timezone (E_CAL_MODEL (model)));
 683 		} else {
 684 			/* we assume that COMPLETED is entered in the current timezone,
 685 			 * even though it gets stored in UTC */
 686 			t = icaltime_as_timet_with_zone (dv->tt, dv->zone);
 687 		}
 688 
 689 		ensure_task_complete (comp_data, t);
 690 	}
 691 }
 692 
 693 static void
 694 set_complete (ECalModelComponent *comp_data,
 695               gconstpointer value)
 696 {
 697 	gint state = GPOINTER_TO_INT (value);
 698 
 699 	if (state)
 700 		ensure_task_complete (comp_data, -1);
 701 	else
 702 		ensure_task_not_complete (comp_data);
 703 }
 704 
 705 static void
 706 set_due (ECalModel *model,
 707          ECalModelComponent *comp_data,
 708          gconstpointer value)
 709 {
 710 	e_cal_model_update_comp_time (model, comp_data, value, ICAL_DUE_PROPERTY, icalproperty_set_due, icalproperty_new_due);
 711 }
 712 
 713 /* FIXME: We need to set the "transient_for" property for the dialog, but the
 714  * model doesn't know anything about the windows.
 715  */
 716 static void
 717 show_geo_warning (void)
 718 {
 719 	GtkWidget *dialog;
 720 
 721 	dialog = gtk_message_dialog_new (
 722 		NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
 723 		"%s", _("The geographical position must be entered "
 724 		"in the format: \n\n45.436845,125.862501"));
 725 	gtk_widget_show (dialog);
 726 }
 727 
 728 static void
 729 set_geo (ECalModelComponent *comp_data,
 730          const gchar *value)
 731 {
 732 	gdouble latitude, longitude;
 733 	gint matched;
 734 	struct icalgeotype geo;
 735 	icalproperty *prop;
 736 
 737 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_GEO_PROPERTY);
 738 
 739 	if (string_is_empty (value)) {
 740 		if (prop) {
 741 			icalcomponent_remove_property (comp_data->icalcomp, prop);
 742 			icalproperty_free (prop);
 743 		}
 744 	} else {
 745 		matched = sscanf (value, "%lg , %lg", &latitude, &longitude);
 746 		if (matched != 2)
 747 			show_geo_warning ();
 748 
 749 		geo.lat = latitude;
 750 		geo.lon = longitude;
 751 		if (prop)
 752 			icalproperty_set_geo (prop, geo);
 753 		else {
 754 			prop = icalproperty_new_geo (geo);
 755 			icalcomponent_add_property (comp_data->icalcomp, prop);
 756 		}
 757 
 758 	}
 759 }
 760 
 761 static void
 762 set_status (ECalModelComponent *comp_data,
 763             const gchar *value)
 764 {
 765 	icalproperty_status status;
 766 	icalproperty *prop;
 767 
 768 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY);
 769 
 770 	/* an empty string is the same as 'None' */
 771 	if (!value[0])
 772 		return;
 773 
 774 	/* Translators: "None" for task's status */
 775 	if (!e_util_utf8_strcasecmp (value, C_("cal-task-status", "None")))
 776 		return;
 777 	else if (!e_util_utf8_strcasecmp (value, _("Not Started")))
 778 		status = ICAL_STATUS_NEEDSACTION;
 779 	else if (!e_util_utf8_strcasecmp (value, _("In Progress")))
 780 		status = ICAL_STATUS_INPROCESS;
 781 	else if (!e_util_utf8_strcasecmp (value, _("Completed")))
 782 		status = ICAL_STATUS_COMPLETED;
 783 	else if (!e_util_utf8_strcasecmp (value, _("Canceled")))
 784 		status = ICAL_STATUS_CANCELLED;
 785 	else {
 786 		g_warning ("Invalid status: %s\n", value);
 787 		return;
 788 	}
 789 
 790 	if (prop)
 791 		icalproperty_set_status (prop, status);
 792 	else {
 793 		prop = icalproperty_new_status (status);
 794 		icalcomponent_add_property (comp_data->icalcomp, prop);
 795 	}
 796 
 797 	switch (status) {
 798 	case ICAL_STATUS_NEEDSACTION:
 799 		ensure_task_not_complete (comp_data);
 800 		break;
 801 
 802 	case ICAL_STATUS_INPROCESS:
 803 		ensure_task_partially_complete (comp_data);
 804 		break;
 805 
 806 	case ICAL_STATUS_CANCELLED:
 807 		ensure_task_not_complete (comp_data);
 808 		/* do this again, because the previous function changed status to NEEDSACTION */
 809 		icalproperty_set_status (prop, status);
 810 		break;
 811 
 812 	case ICAL_STATUS_COMPLETED:
 813 		ensure_task_complete (comp_data, -1);
 814 		break;
 815 	default:
 816 		break;
 817 	}
 818 }
 819 
 820 static void
 821 set_percent (ECalModelComponent *comp_data,
 822              gconstpointer value)
 823 {
 824 	icalproperty *prop;
 825 	gint percent = GPOINTER_TO_INT (value);
 826 
 827 	g_return_if_fail (percent >= -1);
 828 	g_return_if_fail (percent <= 100);
 829 
 830 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY);
 831 
 832 	/* A value of -1 means it isn't set */
 833 	if (percent == -1) {
 834 		if (prop) {
 835 			icalcomponent_remove_property (comp_data->icalcomp, prop);
 836 			icalproperty_free (prop);
 837 		}
 838 		ensure_task_not_complete (comp_data);
 839 	} else {
 840 		if (prop)
 841 			icalproperty_set_percentcomplete (prop, percent);
 842 		else {
 843 			prop = icalproperty_new_percentcomplete (percent);
 844 			icalcomponent_add_property (comp_data->icalcomp, prop);
 845 		}
 846 
 847 		if (percent == 100)
 848 			ensure_task_complete (comp_data, -1);
 849 		else {
 850 			prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
 851 			if (prop) {
 852 				icalcomponent_remove_property (comp_data->icalcomp, prop);
 853 				icalproperty_free (prop);
 854 			}
 855 
 856 			if (percent > 0)
 857 				set_status (comp_data, _("In Progress"));
 858 		}
 859 	}
 860 
 861 }
 862 
 863 static void
 864 set_priority (ECalModelComponent *comp_data,
 865               const gchar *value)
 866 {
 867 	icalproperty *prop;
 868 	gint priority;
 869 
 870 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PRIORITY_PROPERTY);
 871 
 872 	priority = e_cal_util_priority_from_string (value);
 873 	if (priority == -1) {
 874 		g_warning ("Invalid priority");
 875 		priority = 0;
 876 	}
 877 
 878 	if (prop)
 879 		icalproperty_set_priority (prop, priority);
 880 	else {
 881 		prop = icalproperty_new_priority (priority);
 882 		icalcomponent_add_property (comp_data->icalcomp, prop);
 883 	}
 884 }
 885 
 886 static void
 887 set_url (ECalModelComponent *comp_data,
 888          const gchar *value)
 889 {
 890 	icalproperty *prop;
 891 
 892 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_URL_PROPERTY);
 893 
 894 	if (string_is_empty (value)) {
 895 		if (prop) {
 896 			icalcomponent_remove_property (comp_data->icalcomp, prop);
 897 			icalproperty_free (prop);
 898 		}
 899 	} else {
 900 		if (prop)
 901 			icalproperty_set_url (prop, value);
 902 		else {
 903 			prop = icalproperty_new_url (value);
 904 			icalcomponent_add_property (comp_data->icalcomp, prop);
 905 		}
 906 	}
 907 }
 908 
 909 static void
 910 ecmt_set_value_at (ETableModel *etm,
 911                    gint col,
 912                    gint row,
 913                    gconstpointer value)
 914 {
 915 	ECalModelComponent *comp_data;
 916 	ECalModelTasks *model = (ECalModelTasks *) etm;
 917 
 918 	g_return_if_fail (E_IS_CAL_MODEL_TASKS (model));
 919 
 920 	g_return_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST);
 921 	g_return_if_fail (row >= 0 && row < e_table_model_row_count (etm));
 922 
 923 	if (col < E_CAL_MODEL_FIELD_LAST) {
 924 		E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->set_value_at (etm, col, row, value);
 925 		return;
 926 	}
 927 
 928 	comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
 929 	if (!comp_data)
 930 		return;
 931 
 932 	switch (col) {
 933 	case E_CAL_MODEL_TASKS_FIELD_COMPLETED :
 934 		set_completed (model, comp_data, value);
 935 		break;
 936 	case E_CAL_MODEL_TASKS_FIELD_COMPLETE :
 937 		set_complete (comp_data, value);
 938 		break;
 939 	case E_CAL_MODEL_TASKS_FIELD_DUE :
 940 		set_due ((ECalModel *) model, comp_data, value);
 941 		break;
 942 	case E_CAL_MODEL_TASKS_FIELD_GEO :
 943 		set_geo (comp_data, value);
 944 		break;
 945 	case E_CAL_MODEL_TASKS_FIELD_PERCENT :
 946 		set_percent (comp_data, value);
 947 		break;
 948 	case E_CAL_MODEL_TASKS_FIELD_PRIORITY :
 949 		set_priority (comp_data, value);
 950 		break;
 951 	case E_CAL_MODEL_TASKS_FIELD_STATUS :
 952 		set_status (comp_data, value);
 953 		break;
 954 	case E_CAL_MODEL_TASKS_FIELD_URL :
 955 		set_url (comp_data, value);
 956 		break;
 957 	}
 958 
 959 	commit_component_changes (comp_data);
 960 }
 961 
 962 static gboolean
 963 ecmt_is_cell_editable (ETableModel *etm,
 964                        gint col,
 965                        gint row)
 966 {
 967 	ECalModelTasks *model = (ECalModelTasks *) etm;
 968 
 969 	g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), FALSE);
 970 
 971 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, FALSE);
 972 	g_return_val_if_fail (row >= -1 || (row >= 0 && row < e_table_model_row_count (etm)), FALSE);
 973 
 974 	if (col < E_CAL_MODEL_FIELD_LAST)
 975 		return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->is_cell_editable (etm, col, row);
 976 
 977 	if (!e_cal_model_test_row_editable (E_CAL_MODEL (etm), row))
 978 		return FALSE;
 979 
 980 	switch (col) {
 981 	case E_CAL_MODEL_TASKS_FIELD_COMPLETED :
 982 	case E_CAL_MODEL_TASKS_FIELD_COMPLETE :
 983 	case E_CAL_MODEL_TASKS_FIELD_DUE :
 984 	case E_CAL_MODEL_TASKS_FIELD_GEO :
 985 	case E_CAL_MODEL_TASKS_FIELD_PERCENT :
 986 	case E_CAL_MODEL_TASKS_FIELD_PRIORITY :
 987 	case E_CAL_MODEL_TASKS_FIELD_STATUS :
 988 	case E_CAL_MODEL_TASKS_FIELD_URL :
 989 		return TRUE;
 990 	}
 991 
 992 	return FALSE;
 993 }
 994 
 995 static gpointer
 996 ecmt_duplicate_value (ETableModel *etm,
 997                       gint col,
 998                       gconstpointer value)
 999 {
1000 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, NULL);
1001 
1002 	if (col < E_CAL_MODEL_FIELD_LAST)
1003 		return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->duplicate_value (etm, col, value);
1004 
1005 	switch (col) {
1006 	case E_CAL_MODEL_TASKS_FIELD_GEO :
1007 	case E_CAL_MODEL_TASKS_FIELD_PRIORITY :
1008 	case E_CAL_MODEL_TASKS_FIELD_STATUS :
1009 	case E_CAL_MODEL_TASKS_FIELD_URL :
1010 		return g_strdup (value);
1011 	case E_CAL_MODEL_TASKS_FIELD_COMPLETED :
1012 	case E_CAL_MODEL_TASKS_FIELD_DUE :
1013 		if (value) {
1014 			ECellDateEditValue *dv, *orig_dv;
1015 
1016 			orig_dv = (ECellDateEditValue *) value;
1017 			dv = g_new0 (ECellDateEditValue, 1);
1018 			*dv = *orig_dv;
1019 
1020 			return dv;
1021 		}
1022 		break;
1023 
1024 	case E_CAL_MODEL_TASKS_FIELD_COMPLETE :
1025 	case E_CAL_MODEL_TASKS_FIELD_PERCENT :
1026 	case E_CAL_MODEL_TASKS_FIELD_OVERDUE :
1027 		return (gpointer) value;
1028 	}
1029 
1030 	return NULL;
1031 }
1032 
1033 static void
1034 ecmt_free_value (ETableModel *etm,
1035                  gint col,
1036                  gpointer value)
1037 {
1038 	g_return_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST);
1039 
1040 	if (col < E_CAL_MODEL_FIELD_LAST) {
1041 		E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->free_value (etm, col, value);
1042 		return;
1043 	}
1044 
1045 	switch (col) {
1046 	case E_CAL_MODEL_TASKS_FIELD_COMPLETED :
1047 	case E_CAL_MODEL_TASKS_FIELD_DUE :
1048 	case E_CAL_MODEL_TASKS_FIELD_GEO :
1049 	case E_CAL_MODEL_TASKS_FIELD_PRIORITY :
1050 	case E_CAL_MODEL_TASKS_FIELD_STATUS :
1051 	case E_CAL_MODEL_TASKS_FIELD_URL :
1052 		if (value)
1053 			g_free (value);
1054 		break;
1055 	case E_CAL_MODEL_TASKS_FIELD_PERCENT :
1056 	case E_CAL_MODEL_TASKS_FIELD_COMPLETE :
1057 	case E_CAL_MODEL_TASKS_FIELD_OVERDUE :
1058 		break;
1059 	}
1060 }
1061 
1062 static gpointer
1063 ecmt_initialize_value (ETableModel *etm,
1064                        gint col)
1065 {
1066 	ECalModelTasks *model = (ECalModelTasks *) etm;
1067 
1068 	g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), NULL);
1069 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, NULL);
1070 
1071 	if (col < E_CAL_MODEL_FIELD_LAST)
1072 		return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->initialize_value (etm, col);
1073 
1074 	switch (col) {
1075 	case E_CAL_MODEL_TASKS_FIELD_GEO :
1076 	case E_CAL_MODEL_TASKS_FIELD_PRIORITY :
1077 	case E_CAL_MODEL_TASKS_FIELD_STATUS :
1078 	case E_CAL_MODEL_TASKS_FIELD_URL :
1079 		return g_strdup ("");
1080 	case E_CAL_MODEL_TASKS_FIELD_COMPLETED :
1081 	case E_CAL_MODEL_TASKS_FIELD_DUE :
1082 	case E_CAL_MODEL_TASKS_FIELD_COMPLETE :
1083 	case E_CAL_MODEL_TASKS_FIELD_OVERDUE :
1084 		return NULL;
1085 	case E_CAL_MODEL_TASKS_FIELD_PERCENT :
1086 		return GINT_TO_POINTER (-1);
1087 	}
1088 
1089 	return NULL;
1090 }
1091 
1092 static gboolean
1093 ecmt_value_is_empty (ETableModel *etm,
1094                      gint col,
1095                      gconstpointer value)
1096 {
1097 	ECalModelTasks *model = (ECalModelTasks *) etm;
1098 
1099 	g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), TRUE);
1100 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, TRUE);
1101 
1102 	if (col < E_CAL_MODEL_FIELD_LAST)
1103 		return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->value_is_empty (etm, col, value);
1104 
1105 	switch (col) {
1106 	case E_CAL_MODEL_TASKS_FIELD_GEO :
1107 	case E_CAL_MODEL_TASKS_FIELD_PRIORITY :
1108 	case E_CAL_MODEL_TASKS_FIELD_STATUS :
1109 	case E_CAL_MODEL_TASKS_FIELD_URL :
1110 		return string_is_empty (value);
1111 	case E_CAL_MODEL_TASKS_FIELD_COMPLETED :
1112 	case E_CAL_MODEL_TASKS_FIELD_DUE :
1113 		return value ? FALSE : TRUE;
1114 	case E_CAL_MODEL_TASKS_FIELD_PERCENT :
1115 		return (GPOINTER_TO_INT (value) < 0) ? TRUE : FALSE;
1116 	case E_CAL_MODEL_TASKS_FIELD_COMPLETE :
1117 	case E_CAL_MODEL_TASKS_FIELD_OVERDUE :
1118 		return TRUE;
1119 	}
1120 
1121 	return TRUE;
1122 }
1123 
1124 static gchar *
1125 ecmt_value_to_string (ETableModel *etm,
1126                       gint col,
1127                       gconstpointer value)
1128 {
1129 	ECalModelTasks *model = (ECalModelTasks *) etm;
1130 
1131 	g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), g_strdup (""));
1132 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, g_strdup (""));
1133 
1134 	if (col < E_CAL_MODEL_FIELD_LAST)
1135 		return E_TABLE_MODEL_CLASS (e_cal_model_tasks_parent_class)->value_to_string (etm, col, value);
1136 
1137 	switch (col) {
1138 	case E_CAL_MODEL_TASKS_FIELD_GEO :
1139 	case E_CAL_MODEL_TASKS_FIELD_PRIORITY :
1140 	case E_CAL_MODEL_TASKS_FIELD_STATUS :
1141 	case E_CAL_MODEL_TASKS_FIELD_URL :
1142 		return g_strdup (value);
1143 	case E_CAL_MODEL_TASKS_FIELD_COMPLETED :
1144 	case E_CAL_MODEL_TASKS_FIELD_DUE :
1145 		return e_cal_model_date_value_to_string (E_CAL_MODEL (model), value);
1146 	case E_CAL_MODEL_TASKS_FIELD_COMPLETE :
1147 	case E_CAL_MODEL_TASKS_FIELD_OVERDUE :
1148 		return g_strdup (value ? _("Yes") : _("No"));
1149 	case E_CAL_MODEL_TASKS_FIELD_PERCENT :
1150 		if (GPOINTER_TO_INT (value) < 0)
1151 			return g_strdup ("N/A");
1152 		else
1153 			return g_strdup_printf ("%i%%", GPOINTER_TO_INT (value));
1154 	}
1155 
1156 	return g_strdup ("");
1157 }
1158 
1159 /* ECalModel class methods */
1160 
1161 static const gchar *
1162 ecmt_get_color_for_component (ECalModel *model,
1163                               ECalModelComponent *comp_data)
1164 {
1165 	ECalModelTasks *tasks;
1166 
1167 	g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), NULL);
1168 	g_return_val_if_fail (comp_data != NULL, NULL);
1169 
1170 	tasks = E_CAL_MODEL_TASKS (model);
1171 
1172 	/* XXX ECalModel's get_color_for_component() method should really
1173 	 *     get a GdkColor instead of a color specification string. */
1174 
1175 	switch (get_due_status (tasks, comp_data)) {
1176 	case E_CAL_MODEL_TASKS_DUE_TODAY:
1177 		if (!e_cal_model_tasks_get_highlight_due_today (tasks))
1178 			break;
1179 		return e_cal_model_tasks_get_color_due_today (tasks);
1180 	case E_CAL_MODEL_TASKS_DUE_OVERDUE:
1181 		if (!e_cal_model_tasks_get_highlight_overdue (tasks))
1182 			break;
1183 		return e_cal_model_tasks_get_color_overdue (tasks);
1184 	case E_CAL_MODEL_TASKS_DUE_NEVER:
1185 	case E_CAL_MODEL_TASKS_DUE_FUTURE:
1186 	case E_CAL_MODEL_TASKS_DUE_COMPLETE:
1187 		break;
1188 	}
1189 
1190 	return E_CAL_MODEL_CLASS (e_cal_model_tasks_parent_class)->
1191 		get_color_for_component (model, comp_data);
1192 }
1193 
1194 static void
1195 ecmt_fill_component_from_model (ECalModel *model,
1196                                 ECalModelComponent *comp_data,
1197                                 ETableModel *source_model,
1198                                 gint row)
1199 {
1200 	gpointer value;
1201 
1202 	g_return_if_fail (E_IS_CAL_MODEL_TASKS (model));
1203 	g_return_if_fail (comp_data != NULL);
1204 	g_return_if_fail (E_IS_TABLE_MODEL (source_model));
1205 
1206 	/* This just makes sure if anything indicates completion, all
1207 	 * three fields do or if percent is 0, status is sane */
1208 
1209 	value = e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_COMPLETED, row);
1210 	set_completed ((ECalModelTasks *) model, comp_data, value);
1211 	if (!value) {
1212 		value = e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_PERCENT, row);
1213 		set_percent (comp_data, value);
1214 		if (GPOINTER_TO_INT (value) != 100 && GPOINTER_TO_INT (value) != 0)
1215 			set_status (comp_data, e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_STATUS, row));
1216 	}
1217 
1218 	set_due (
1219 		model, comp_data,
1220 		e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_DUE, row));
1221 	set_geo (
1222 		comp_data,
1223 		e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_GEO, row));
1224 	set_priority (
1225 		comp_data,
1226 		e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_PRIORITY, row));
1227 	set_url (
1228 		comp_data,
1229 		e_table_model_value_at (source_model, E_CAL_MODEL_TASKS_FIELD_URL, row));
1230 }
1231 
1232 ECalModel *
1233 e_cal_model_tasks_new (ESourceRegistry *registry)
1234 {
1235 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
1236 
1237 	return g_object_new (
1238 		E_TYPE_CAL_MODEL_TASKS,
1239 		"registry", registry, NULL);
1240 }
1241 
1242 gboolean
1243 e_cal_model_tasks_get_highlight_due_today (ECalModelTasks *model)
1244 {
1245 	g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), FALSE);
1246 
1247 	return model->priv->highlight_due_today;
1248 }
1249 
1250 void
1251 e_cal_model_tasks_set_highlight_due_today (ECalModelTasks *model,
1252                                            gboolean highlight)
1253 {
1254 	g_return_if_fail (E_IS_CAL_MODEL_TASKS (model));
1255 
1256 	if (model->priv->highlight_due_today == highlight)
1257 		return;
1258 
1259 	model->priv->highlight_due_today = highlight;
1260 
1261 	g_object_notify (G_OBJECT (model), "highlight-due-today");
1262 }
1263 
1264 const gchar *
1265 e_cal_model_tasks_get_color_due_today (ECalModelTasks *model)
1266 {
1267 	g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), NULL);
1268 
1269 	return model->priv->color_due_today;
1270 }
1271 
1272 void
1273 e_cal_model_tasks_set_color_due_today (ECalModelTasks *model,
1274                                        const gchar *color_due_today)
1275 {
1276 	g_return_if_fail (E_IS_CAL_MODEL_TASKS (model));
1277 	g_return_if_fail (color_due_today != NULL);
1278 
1279 	if (g_strcmp0 (model->priv->color_due_today, color_due_today) == 0)
1280 		return;
1281 
1282 	g_free (model->priv->color_due_today);
1283 	model->priv->color_due_today = g_strdup (color_due_today);
1284 
1285 	g_object_notify (G_OBJECT (model), "color-due-today");
1286 }
1287 
1288 gboolean
1289 e_cal_model_tasks_get_highlight_overdue (ECalModelTasks *model)
1290 {
1291 	g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), FALSE);
1292 
1293 	return model->priv->highlight_overdue;
1294 }
1295 
1296 void
1297 e_cal_model_tasks_set_highlight_overdue (ECalModelTasks *model,
1298                                          gboolean highlight)
1299 {
1300 	g_return_if_fail (E_IS_CAL_MODEL_TASKS (model));
1301 
1302 	if (model->priv->highlight_overdue == highlight)
1303 		return;
1304 
1305 	model->priv->highlight_overdue = highlight;
1306 
1307 	g_object_notify (G_OBJECT (model), "highlight-overdue");
1308 }
1309 
1310 const gchar *
1311 e_cal_model_tasks_get_color_overdue (ECalModelTasks *model)
1312 {
1313 	g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), NULL);
1314 
1315 	return model->priv->color_overdue;
1316 }
1317 
1318 void
1319 e_cal_model_tasks_set_color_overdue (ECalModelTasks *model,
1320                                      const gchar *color_overdue)
1321 {
1322 	g_return_if_fail (E_IS_CAL_MODEL_TASKS (model));
1323 	g_return_if_fail (color_overdue != NULL);
1324 
1325 	if (g_strcmp0 (model->priv->color_overdue, color_overdue) == 0)
1326 		return;
1327 
1328 	g_free (model->priv->color_overdue);
1329 	model->priv->color_overdue = g_strdup (color_overdue);
1330 
1331 	g_object_notify (G_OBJECT (model), "color-overdue");
1332 }
1333 
1334 /**
1335  * e_cal_model_tasks_mark_comp_complete
1336  * @model: Currently not used...
1337  * @comp_data: Component of our interest
1338  *
1339  * Marks component as complete and commits changes to the calendar backend.
1340  **/
1341 void e_cal_model_tasks_mark_comp_complete (ECalModelTasks *model, ECalModelComponent *comp_data)
1342 {
1343 	g_return_if_fail (model != NULL);
1344 	g_return_if_fail (comp_data != NULL);
1345 
1346 	/* we will receive changes when committed, so don't do this */
1347 	/*e_table_model_pre_change (E_TABLE_MODEL (model));*/
1348 
1349 	ensure_task_complete (comp_data, -1);
1350 
1351 	/*e_table_model_row_changed (E_TABLE_MODEL (model), model_row);*/
1352 
1353 	commit_component_changes (comp_data);
1354 }
1355 
1356 /**
1357  * e_cal_model_tasks_mark_comp_incomplete
1358  * @model: Currently not used...
1359  * @comp_data: Component of our interest
1360  *
1361  * Marks component as incomplete and commits changes to the calendar backend.
1362  **/
1363 void e_cal_model_tasks_mark_comp_incomplete (ECalModelTasks *model, ECalModelComponent *comp_data)
1364 {
1365 	icalproperty *prop,*prop1;
1366 
1367 	g_return_if_fail (model != NULL);
1368 	g_return_if_fail (comp_data != NULL);
1369 
1370 	/* we will receive changes when committed, so don't do this */
1371 	/*e_table_model_pre_change (E_TABLE_MODEL (model));*/
1372 
1373 	/* Status */
1374 	prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY);
1375 	if (prop)
1376 		icalproperty_set_status (prop, ICAL_STATUS_NEEDSACTION);
1377 	else
1378 		icalcomponent_add_property (comp_data->icalcomp, icalproperty_new_status (ICAL_STATUS_NEEDSACTION));
1379 
1380 	/*complete property*/
1381 	prop1 = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
1382 	if (prop1) {
1383 		icalcomponent_remove_property (comp_data->icalcomp, prop1);
1384 		icalproperty_free (prop1);
1385 	}
1386 
1387 	/* Percent. */
1388 	prop1 = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY);
1389 	if (prop1) {
1390 		icalcomponent_remove_property (comp_data->icalcomp, prop1);
1391 		icalproperty_free (prop1);
1392 	}
1393 
1394 	/*e_table_model_row_changed (E_TABLE_MODEL (model), model_row);*/
1395 
1396 	commit_component_changes (comp_data);
1397 }
1398 
1399 /**
1400  * commit_component_changes
1401  * @comp_data: Component of our interest, which has been changed.
1402  *
1403  * Commits changes to the backend calendar of the component.
1404  **/
1405 static void
1406 commit_component_changes (ECalModelComponent *comp_data)
1407 {
1408 	GError *error = NULL;
1409 
1410 	g_return_if_fail (comp_data != NULL);
1411 
1412 	/* FIXME ask about mod type */
1413 	e_cal_client_modify_object_sync (
1414 		comp_data->client, comp_data->icalcomp,
1415 		CALOBJ_MOD_ALL, NULL, &error);
1416 
1417 	if (error != NULL) {
1418 		g_warning (
1419 			G_STRLOC ": Could not modify the object! %s",
1420 			error->message);
1421 
1422 		/* FIXME Show error dialog */
1423 		g_error_free (error);
1424 	}
1425 }
1426 
1427 /**
1428  * e_cal_model_tasks_update_due_tasks
1429  */
1430 void
1431 e_cal_model_tasks_update_due_tasks (ECalModelTasks *model)
1432 {
1433 	gint row, row_count;
1434 	ECalModelComponent *comp_data;
1435 	ECalModelTasksDueStatus status;
1436 
1437 	g_return_if_fail (E_IS_CAL_MODEL_TASKS (model));
1438 
1439 	row_count = e_table_model_row_count (E_TABLE_MODEL (model));
1440 
1441 	for (row = 0; row < row_count; row++)
1442 	{
1443 		comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
1444 		status = get_due_status (E_CAL_MODEL_TASKS (model), comp_data);
1445 		if ((status == E_CAL_MODEL_TASKS_DUE_TODAY) || (status == E_CAL_MODEL_TASKS_DUE_OVERDUE))
1446 		{
1447 			e_table_model_pre_change (E_TABLE_MODEL (model));
1448 			e_table_model_row_changed (E_TABLE_MODEL (model), row);
1449 		}
1450 	}
1451 }