From beea88e5feb6f14b4912c6aa4878c39a7632977c Mon Sep 17 00:00:00 2001
From: Lukas Fleischer <lfleischer@calcurse.org>
Date: Sun, 17 Jan 2016 22:46:24 +0100
Subject: Use a separate field for the completed status

Add a new field that indicates whether a todo item is completed or not
instead of encoding completed todo items by negative priorities.

Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
---
 src/calcurse.h |  3 ++-
 src/ical.c     | 18 +++++++-----------
 src/io.c       | 19 ++++++++++++++-----
 src/pcal.c     |  2 +-
 src/todo.c     | 30 ++++++++++--------------------
 src/ui-todo.c  | 11 ++++++-----
 6 files changed, 40 insertions(+), 43 deletions(-)

(limited to 'src')

diff --git a/src/calcurse.h b/src/calcurse.h
index 27fcc68..67f95fa 100644
--- a/src/calcurse.h
+++ b/src/calcurse.h
@@ -323,6 +323,7 @@ struct event {
 struct todo {
 	char *mesg;
 	int id;
+	int completed;
 	char *note;
 };
 
@@ -1017,7 +1018,7 @@ int string_printf(struct string *, const char *, ...);
 /* todo.c */
 extern llist_t todolist;
 struct todo *todo_get_item(int, int);
-struct todo *todo_add(char *, int, char *);
+struct todo *todo_add(char *, int, int, char *);
 char *todo_tostr(struct todo *);
 char *todo_hash(struct todo *);
 void todo_write(struct todo *, FILE *);
diff --git a/src/ical.c b/src/ical.c
index 93952ec..dfb5dd7 100644
--- a/src/ical.c
+++ b/src/ical.c
@@ -266,14 +266,11 @@ static void ical_export_todo(FILE * stream, int export_uid)
 
 	LLIST_FOREACH(&todolist, i) {
 		struct todo *todo = LLIST_TS_GET_DATA(i);
-		int priority = todo->id;
 
 		fputs("BEGIN:VTODO\n", stream);
-		if (todo->id < 0) {
+		if (todo->completed)
 			fprintf(stream, "STATUS:COMPLETED\n");
-			priority = -priority;
-		}
-		fprintf(stream, "PRIORITY:%d\n", priority);
+		fprintf(stream, "PRIORITY:%d\n", todo->id);
 		fprintf(stream, "SUMMARY:%s\n", todo->mesg);
 
 		if (export_uid) {
@@ -327,9 +324,10 @@ static void ical_log(FILE * log, ical_types_e type, unsigned lineno,
 	fprintf(log, "%s [%d]: %s\n", typestr[type], lineno, msg);
 }
 
-static void ical_store_todo(int priority, char *mesg, char *note, int list)
+static void ical_store_todo(int priority, int completed, char *mesg,
+			    char *note, int list)
 {
-	struct todo *todo = todo_add(mesg, priority, note);
+	struct todo *todo = todo_add(mesg, priority, completed, note);
 	if (list) {
 		char *hash = todo_hash(todo);
 		printf("%s\n", hash);
@@ -1081,16 +1079,14 @@ ical_read_todo(FILE * fdi, FILE * log, int list, unsigned *notodos,
 		if (starts_with_ci(buf, "END:VTODO")) {
 			if (!vtodo.has_priority)
 				vtodo.priority = LOWEST;
-			if (vtodo.completed)
-				vtodo.priority = -vtodo.priority;
 			if (!vtodo.mesg) {
 				ical_log(log, ICAL_VTODO, ITEMLINE,
 					 _("could not retrieve item summary."));
 				goto cleanup;
 			}
 
-			ical_store_todo(vtodo.priority, vtodo.mesg,
-					vtodo.note, list);
+			ical_store_todo(vtodo.priority, vtodo.completed,
+					vtodo.mesg, vtodo.note, list);
 			(*notodos)++;
 			return;
 		}
diff --git a/src/io.c b/src/io.c
index b0eca77..4ff16cd 100644
--- a/src/io.c
+++ b/src/io.c
@@ -630,7 +630,7 @@ void io_load_todo(struct item_filter *filter)
 	FILE *data_file;
 	char *newline;
 	int nb_tod = 0;
-	int c, id;
+	int c, id, completed;
 	char buf[BUFSIZ], e_todo[BUFSIZ], note[MAX_NOTESIZ + 1];
 	unsigned line = 0;
 
@@ -642,7 +642,15 @@ void io_load_todo(struct item_filter *filter)
 		c = getc(data_file);
 		if (c == EOF) {
 			break;
-		} else if (c == '[') {	/* new style with id */
+		} else if (c == '[') {
+			/* new style with id */
+			c = getc(data_file);
+			if (c == '-') {
+				completed = 1;
+			} else {
+				completed = 0;
+				ungetc(c, data_file);
+			}
 			if (fscanf(data_file, " %d ", &id) != 1
 			    || getc(data_file) != ']')
 				io_load_error(path_todo, line,
@@ -651,6 +659,7 @@ void io_load_todo(struct item_filter *filter)
 			ungetc(c, data_file);
 		} else {
 			id = 9;
+			completed = 0;
 			ungetc(c, data_file);
 		}
 		/* Now read the attached note, if any. */
@@ -678,13 +687,13 @@ void io_load_todo(struct item_filter *filter)
 				continue;
 			if (filter->priority && id != filter->priority)
 				continue;
-			if (filter->completed && id > 0)
+			if (filter->completed && !completed)
 				continue;
-			if (filter->uncompleted && id < 0)
+			if (filter->uncompleted && completed)
 				continue;
 		}
 
-		struct todo *todo = todo_add(e_todo, id, note);
+		struct todo *todo = todo_add(e_todo, id, completed, note);
 
 		/* Filter by hash. */
 		if (filter && filter->hash) {
diff --git a/src/pcal.c b/src/pcal.c
index db85e1c..1c76aa0 100644
--- a/src/pcal.c
+++ b/src/pcal.c
@@ -311,7 +311,7 @@ static void pcal_export_todo(FILE * stream)
 	fputs("#\n# Todos\n#\n", stream);
 	LLIST_FOREACH(&todolist, i) {
 		struct todo *todo = LLIST_TS_GET_DATA(i);
-		if (todo->id < 0)	/* completed items */
+		if (todo->completed)
 			continue;
 
 		fputs("note all  ", stream);
diff --git a/src/todo.c b/src/todo.c
index 707628c..cd0eed7 100644
--- a/src/todo.c
+++ b/src/todo.c
@@ -45,7 +45,7 @@ llist_t todolist;
 
 static int todo_is_uncompleted(struct todo *todo, void *cbdata)
 {
-	return todo->id >= 0;
+	return !todo->completed;
 }
 
 /* Returns a structure containing the selected item. */
@@ -64,27 +64,20 @@ struct todo *todo_get_item(int item_number, int skip_completed)
 
 static int todo_cmp_id(struct todo *a, struct todo *b)
 {
-	/*
-	 * As of version 2.6, todo items can have a negative id, which means they
-	 * were completed. To keep them sorted, we need to consider the absolute id
-	 * value.
-	 */
-	int abs_a = abs(a->id);
-	int abs_b = abs(b->id);
-
-	return abs_a < abs_b ? -1 : (abs_a == abs_b ? 0 : 1);
+	return a->id - b->id;
 }
 
 /*
  * Add an item in the todo linked list.
  */
-struct todo *todo_add(char *mesg, int id, char *note)
+struct todo *todo_add(char *mesg, int id, int completed, char *note)
 {
 	struct todo *todo;
 
 	todo = mem_malloc(sizeof(struct todo));
 	todo->mesg = mem_strdup(mesg);
 	todo->id = id;
+	todo->completed = completed;
 	todo->note = (note != NULL
 		      && note[0] != '\0') ? mem_strdup(note) : NULL;
 
@@ -96,11 +89,13 @@ struct todo *todo_add(char *mesg, int id, char *note)
 char *todo_tostr(struct todo *todo)
 {
 	char *res;
+	const char *cstr = todo->completed ? "-" : "";
 
 	if (todo->note)
-		asprintf(&res, "[%d]>%s %s", todo->id, todo->note, todo->mesg);
+		asprintf(&res, "[%s%d]>%s %s", cstr, todo->id, todo->note,
+			 todo->mesg);
 	else
-		asprintf(&res, "[%d] %s", todo->id, todo->mesg);
+		asprintf(&res, "[%s%d] %s", cstr, todo->id, todo->mesg);
 
 	return res;
 }
@@ -144,15 +139,10 @@ void todo_delete(struct todo *todo)
 	mem_free(todo);
 }
 
-/*
- * Flag a todo item (for now on, only the 'completed' state is available).
- * Internally, a completed item keeps its priority, but it becomes negative.
- * This way, it is easy to retrive its original priority if the user decides
- * that in fact it was not completed.
- */
+/* Flag a todo item. */
 void todo_flag(struct todo *t)
 {
-	t->id = -t->id;
+	t->completed = !t->completed;
 }
 
 /*
diff --git a/src/ui-todo.c b/src/ui-todo.c
index 86592c1..2a03844 100644
--- a/src/ui-todo.c
+++ b/src/ui-todo.c
@@ -60,7 +60,7 @@ void ui_todo_add(void)
 			status_mesg(mesg_id, "");
 			ch = wgetch(win[KEY].p);
 		}
-		todo_add(todo_input, ch - '0', NULL);
+		todo_add(todo_input, ch - '0', 0, NULL);
 		ui_todo_load_items();
 		io_set_modified();
 	}
@@ -163,14 +163,14 @@ void ui_todo_draw(int n, WINDOW *win, int y, int hilt, void *cb_data)
 	int j;
 
 	if (ui_todo_view == TODO_HIDE_COMPLETED_VIEW) {
-		while (i && todo->id < 0) {
+		while (i && todo->completed) {
 			i = i->next;
 			if (i)
 				todo = LLIST_TS_GET_DATA(i);
 		}
 	}
 
-	mark[0] = todo->id > 0 ? '0' + todo->id : 'X';
+	mark[0] = todo->completed ? 'X' : '0' + todo->id;
 	mark[1] = todo->note ? '>' : '.';
 
 	hilt = hilt && (wins_slctd() == TOD);
@@ -217,7 +217,8 @@ void ui_todo_load_items(void)
 	/* TODO: Optimize this by keeping the list size in a variable. */
 	LLIST_FOREACH(&todolist, i) {
 		struct todo *todo = LLIST_TS_GET_DATA(i);
-		if (ui_todo_view == TODO_HIDE_COMPLETED_VIEW && todo->id < 0)
+		if (ui_todo_view == TODO_HIDE_COMPLETED_VIEW &&
+		    todo->completed)
 			continue;
 		n++;
 	}
@@ -263,7 +264,7 @@ void ui_todo_chg_priority(int diff)
 	else if (id > 9)
 		id = 9;
 
-	item_new = todo_add(item->mesg, id, item->note);
+	item_new = todo_add(item->mesg, id, item->completed, item->note);
 	todo_delete(item);
 	io_set_modified();
 	listbox_set_sel(&lb_todo, todo_get_position(item_new));
-- 
cgit v1.2.3-70-g09d2