Updated Spanish translation
[anjuta-git-plugin.git] / plugins / gtodo / libgtodo.c
blob43b3239fe24f2b988a4214a758129ecb734889ab
1 #include <glib.h>
2 #include <string.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <time.h>
7 #include <libxml/parser.h>
8 #include <libxml/tree.h>
9 #include "libgtodo.h"
10 #include <libgnomevfs/gnome-vfs.h>
12 #ifdef ENABLE_NLS
13 #include <libintl.h>
14 #include <locale.h>
15 #define _(String) gettext (String)
16 # ifdef gettext_noop
17 # define N_(String) gettext_noop (String)
18 # else
19 # define N_(String) (String)
20 # endif
21 #else
22 #define _(String) String
23 #endif
25 #ifdef DEBUG
26 short int debug = 1;
27 #else
28 short int debug = 0;
29 #endif
31 typedef struct _GTodoCategory{
32 gchar *name;
33 gint id;
34 } GTodoCategory;
36 /* should not be used by the user. internal function */
37 GTodoItem * gtodo_client_get_todo_item_from_xml_ptr(GTodoClient *cl, xmlNodePtr node);
39 /* this checks if the xml backend file exists.. not to be used by the user */
40 int check_item_changed(GnomeVFSMonitorHandle *handle, const gchar *uri, const gchar *info, GnomeVFSMonitorEventType event, GTodoClient *cl);
42 int gtodo_client_check_file(GTodoClient *cl, GError **error);
45 /* Function that creates an empty todo item. WARNING Don't use this when adding a todo item to the list.*/
46 /* Use gtodo_client_create_new_todo_item instead */
47 /* note.. id is equal to the time created... this should be unique. (what is the change on 2 pc's its created at the vary same second )*/
49 GTodoItem * gtodo_client_create_empty_todo_item(void)
51 GTodoItem *item = g_malloc(sizeof(GTodoItem));
52 if(item == NULL) return NULL;
53 item->id = 0;
54 item->notify = FALSE;
55 item->last_edited = 0;
56 item->start = NULL;
57 item->stop = NULL;
58 item->due = NULL;
59 item->done = FALSE;
60 item->category = NULL;
61 item->priority = GTODO_PRIORITY_MEDIUM;
62 item->summary = NULL;
63 item->comment = NULL;
64 item->due_time[GTODO_DUE_TIME_HOURE] = -1;
65 item->due_time[GTODO_DUE_TIME_MINUTE] = 0;
66 return item;
69 /* create a new unique todo item */
70 /* use this to add an todo item */
71 GTodoItem * gtodo_client_create_new_todo_item(GTodoClient *cl)
73 GTodoItem *item = gtodo_client_create_empty_todo_item();
74 /* give an nice "random" id */
75 item->id = (GTime)time(NULL);
76 /* set the start time */
77 item->start = g_date_new();
78 g_date_set_time(item->start, (GTime)item->id);
79 return item;
83 /* free's an GTodoItem */
84 void gtodo_todo_item_free(GTodoItem *item)
86 if(item->start != NULL) g_date_free(item->start);
87 if(item->stop != NULL) g_date_free(item->stop);
88 if(item->due != NULL) g_date_free(item->due);
89 if(item->category != NULL) g_free(item->category);
90 if(item->summary != NULL) g_free(item->summary);
91 if(item->comment != NULL) g_free(item->comment);
92 g_free(item);
96 /* get the id from an todo item in guint32 (its an GTime, but a gtime is an gint32)..*/
97 /* I made it a guint32 because there is no negative time here */
98 guint32 gtodo_todo_item_get_id(GTodoItem *item)
100 return (guint32 )item->id;
103 /* set the notification flag for this todo item. */
104 void gtodo_todo_item_set_notify(GTodoItem *item, gboolean notify)
106 item->notify = notify;
108 /* get the statis of the notification flag */
109 gboolean gtodo_todo_item_get_notify(GTodoItem *item)
111 return item->notify;
114 /* get the priority. see enumeration in libgtodo.h for possible return values */
115 int gtodo_todo_item_get_priority(GTodoItem *item)
117 return item->priority;
120 /* set the priority, for possible value's look @ enumeration in libgtodo.c */
121 void gtodo_todo_item_set_priority(GTodoItem *item, int priority)
123 item->priority = priority;
126 /* get the summary, the returned value shouldnt be freed.*/
127 /* I return an empty string when there is no value. I am afraid this is wrong now */
129 char *gtodo_todo_item_get_summary(GTodoItem *item)
131 if(item->summary == NULL) return "";
132 return item->summary;
135 /* set the summary, also setting to NULL, or changing is allowed */
136 void gtodo_todo_item_set_summary(GTodoItem *item, gchar *summary)
138 if(summary == NULL)
140 if(item->summary != NULL) g_free(item->summary);
141 item->summary = NULL;
143 else
145 GString *string;
146 int i;
147 string = g_string_new(summary);
148 for(i=0;i < string->len;i++)
150 if(string->str[i] == '&')
152 g_string_insert(string, i+1, "amp;");
155 if(item->summary != NULL) g_free(item->summary);
156 item->summary = string->str;
157 g_string_free(string,FALSE);
161 /* get the category, the returned value shouldnt be freeed.*/
162 char *gtodo_todo_item_get_category(GTodoItem *item)
164 return item->category;
167 /* set the category or changing is allowed */
168 /* FIXME if category exists, if not.. create it. */
169 void gtodo_todo_item_set_category(GTodoItem *item, gchar *category)
171 if(category == NULL) return;
172 /* setting to NULL is bad.. because the GTodoItem is invalid then */
173 /* {
174 if(item->category != NULL) g_free(item->category);
175 item->category = NULL;
177 */ else
179 if(item->category != NULL) g_free(item->category);
180 item->category = g_strdup(category);
184 /* get the comment, this can be a multi line string */
185 char *gtodo_todo_item_get_comment(GTodoItem *item)
187 if(item->comment == NULL) return "";
188 return item->comment;
191 /* set the comment, setting to NULL is allowed, or changing */
192 void gtodo_todo_item_set_comment(GTodoItem *item, gchar *comment)
194 if(comment == NULL)
196 if(item->comment != NULL) g_free(item->comment);
197 item->comment = NULL;
199 else{
200 GString *string;
201 int i;
202 string = g_string_new(comment);
203 for(i=0;i < string->len;i++)
205 if(string->str[i] == '&')
207 g_string_insert(string, i+1, "amp;");
210 if(item->comment != NULL) g_free(item->comment);
211 item->comment = string->str;
212 g_string_free(string, FALSE);
216 /*get/set done */
217 gboolean gtodo_todo_item_get_done(GTodoItem *item)
219 return item->done;
222 void gtodo_todo_item_set_done(GTodoItem *item, gboolean done)
224 /* if the item is set done, set done date aswell, useless to have the user set it twice */
225 if(done == TRUE) gtodo_todo_item_set_stop_date_today(item);
226 item->done = done;
229 /* > 0 allready due */
230 /* 0 due today */
231 /* <0 due in future */
232 /* GTODO_NO_DUE_DATE = no due date */
233 gint32 gtodo_todo_item_check_due(GTodoItem *item)
235 GDate *today;
236 int i;
237 if(item->due == NULL) return GTODO_NO_DUE_DATE;
238 today = g_date_new();
239 g_date_set_time(today, time(NULL));
240 i = g_date_days_between(item->due,today);
241 g_date_free(today);
242 return i;
244 /*returns the time in minutes that is still left.. it will return 0 when there is nothing left
245 ofit isnt today. */
247 int gtodo_todo_item_check_due_time_minutes_left(GTodoItem *item)
249 struct tm *lctime;
250 time_t now;
251 if(gtodo_todo_item_check_due(item) != 0) return 0;
252 now = time(NULL);
253 lctime = localtime(&now);
254 if(lctime == NULL) return 0;
255 if(item->due_time[GTODO_DUE_TIME_HOURE] == -1 && item->due_time[GTODO_DUE_TIME_MINUTE] == 0) return 3000;
256 return MAX(0, -((lctime->tm_hour*60+lctime->tm_min) - item->due_time[GTODO_DUE_TIME_HOURE]*60-item->due_time[GTODO_DUE_TIME_MINUTE]));
259 /* get the last_edited date in severall format's */
260 /* return an julian date ... -1 = no date set */
261 guint32 gtodo_todo_item_get_last_edited_date_as_julian(GTodoItem *item)
263 if(item->last_edited == 0 ) return 1;
264 else
266 GDate *date = g_date_new();
267 guint32 julian=1;
268 g_date_set_time(date, item->last_edited);
269 julian = g_date_get_julian(date);
270 g_date_free(date);
271 return julian;
274 /* return the houre of the due time */
275 gint gtodo_todo_item_get_due_time_houre(GTodoItem *item)
277 return item->due_time[GTODO_DUE_TIME_HOURE];
279 /* return the houre of the due time */
280 gint gtodo_todo_item_get_due_time_minute(GTodoItem *item)
282 return item->due_time[GTODO_DUE_TIME_MINUTE];
284 /* return the houre of the due time */
285 gint gtodo_todo_item_set_due_time_minute(GTodoItem *item, gint minute)
287 if(minute < 0 && minute >=60 ) return FALSE;
288 else item->due_time[GTODO_DUE_TIME_MINUTE] = minute;
289 return TRUE;
291 /* return the houre of the due time */
292 gint gtodo_todo_item_set_due_time_houre(GTodoItem *item, gint houre)
294 if(houre < -1 && houre >= 24 ) return FALSE;
295 else item->due_time[GTODO_DUE_TIME_HOURE] = houre;
296 return TRUE;
298 /* get the start date in severall format's */
299 /* return an julian date ... -1 = no date set */
300 guint32 gtodo_todo_item_get_start_date_as_julian(GTodoItem *item)
302 if(item->start == NULL || !g_date_valid(item->start)) return 1;
303 else
305 if(!g_date_valid_julian(g_date_get_julian(item->start))) return 1;
306 return g_date_get_julian(item->start);
309 /* set start date returns false when not able to set */
310 gboolean gtodo_todo_item_set_start_date_as_julian(GTodoItem *item, guint32 julian)
312 if(!g_date_valid_julian(julian)) return FALSE;
313 if(item->start == NULL) item->start = g_date_new_julian(julian);
314 else g_date_set_julian(item->start, julian);
315 return TRUE;
319 /* get localized string.. this needs to be freed! */
320 gchar *gtodo_todo_item_get_start_date_as_string(GTodoItem *item)
322 gchar *buffer = g_malloc(sizeof(gchar)*64);
323 memset(buffer,'\0', 64*sizeof(gchar));
324 if(item == NULL || item->start == NULL)
326 g_free(buffer);
327 return NULL;
329 if(!g_date_valid(item->start))
331 g_free(buffer);
332 return NULL;
334 if(g_date_strftime(buffer, 64*sizeof(gchar), "%d %b %G", item->start) == 0)
336 g_free(buffer);
337 return NULL;
339 return buffer;
342 /* get the stop date in severall format's */
343 /* return an julian date ... 1 = no date set */
344 guint32 gtodo_todo_item_get_stop_date_as_julian(GTodoItem *item)
346 if(item->stop == NULL || !g_date_valid(item->stop)) return 1;
347 else
349 if(!g_date_valid_julian(g_date_get_julian(item->stop))) return 1;
350 return g_date_get_julian(item->stop);
354 /* set stop date returns false when not able to set */
355 gboolean gtodo_todo_item_set_stop_date_as_julian(GTodoItem *item, guint32 julian)
357 if(!g_date_valid_julian(julian)) return FALSE;
358 if(item->stop == NULL) item->stop = g_date_new_julian(julian);
359 else g_date_set_julian(item->stop, julian);
360 return TRUE;
362 gboolean gtodo_todo_item_set_stop_date_today(GTodoItem *item)
364 if(item == NULL) return FALSE;
365 if(item->stop == NULL) item->stop = g_date_new();
366 g_date_set_time(item->stop, time(NULL));
367 return TRUE;
369 /* get localized string.. this needs to be freed! */
370 gchar *gtodo_todo_item_get_stop_date_as_string(GTodoItem *item)
372 gchar *buffer = g_malloc(sizeof(gchar)*64);
373 memset(buffer, '\0', 64*sizeof(gchar));
374 if(item == NULL || item->stop == NULL)
376 g_free(buffer);
377 return NULL;
379 if(!g_date_valid(item->stop))
381 g_free(buffer);
382 return NULL;
384 if(g_date_strftime(buffer, 64*sizeof(gchar), "%d %b %G", item->stop) == 0)
386 g_free(buffer);
387 return NULL;
389 return buffer;
391 /* get the due date in severall format's */
392 /* return an julian date ... 1 = no date set */
393 guint32 gtodo_todo_item_get_due_date_as_julian(GTodoItem *item)
395 if(item->due == NULL || !g_date_valid(item->due))
397 return GTODO_NO_DUE_DATE;
399 else
401 if(!g_date_valid_julian(g_date_get_julian(item->due))) return GTODO_NO_DUE_DATE;
402 return g_date_get_julian(item->due);
406 /* set due date returns false when not able to set */
407 gboolean gtodo_todo_item_set_due_date_as_julian(GTodoItem *item, guint32 julian)
409 if(julian == GTODO_NO_DUE_DATE)
411 if(item->due != NULL)
413 g_date_free(item->due);
414 item->due = NULL;
417 if(!g_date_valid_julian((guint32)julian)) return FALSE;
418 if(item->due == NULL) item->due = g_date_new_julian((guint32)julian);
419 else g_date_set_julian(item->due, (guint32)julian);
420 return TRUE;
423 GDate * gtodo_todo_item_get_due_date(GTodoItem *item)
425 if(item == NULL || item->due == NULL) return NULL;
426 if(!g_date_valid(item->due)) return NULL;
427 return item->due;
430 /* get localized string.. this needs to be freed! */
431 gchar *gtodo_todo_item_get_due_date_as_string(GTodoItem *item)
433 gchar *buffer = g_malloc(sizeof(gchar)*64);
434 memset(buffer, '\0', 64*sizeof(gchar));
435 if(item == NULL || item->due == NULL)
437 g_free(buffer);
438 return NULL;
440 if(!g_date_valid(item->due))
442 g_free(buffer);
443 return NULL;
445 if(g_date_strftime(buffer, 64*sizeof(gchar), "%d %b %G", item->due) == 0)
447 g_free(buffer);
448 return NULL;
450 return buffer;
453 /* should not be used by the user. internal function */
454 GTodoItem * gtodo_client_get_todo_item_from_xml_ptr(GTodoClient *cl, xmlNodePtr node)
456 GTodoItem *item =NULL;
457 xmlChar *category;
458 if(node == NULL) return NULL;
459 category = xmlGetProp(node->parent, (const xmlChar *)"title");
460 node = node->xmlChildrenNode;
461 item = gtodo_client_create_empty_todo_item();
462 gtodo_todo_item_set_category(item, (gchar *)category);
463 xmlFree(category);
464 while(node != NULL)
466 if(xmlStrEqual(node->name, (const xmlChar *)"comment"))
468 xmlChar *temp;
469 temp = xmlNodeGetContent(node);
470 if(temp != NULL)
472 item->comment = g_strdup((gchar *)temp);
473 xmlFree(temp);
476 else if(xmlStrEqual(node->name, (const xmlChar *)"summary"))
478 xmlChar *temp;
479 temp = xmlNodeGetContent(node);
480 if(temp != NULL)
482 item->summary = g_strdup((gchar *)temp);
483 xmlFree(temp);
486 else if(xmlStrEqual(node->name, (const xmlChar *)"attribute"))
488 xmlChar *temp;
489 temp = xmlGetProp(node, (const xmlChar *)"id");
490 if(temp != NULL)
492 item->id = g_ascii_strtoull((gchar *)temp, NULL,0);
493 xmlFree(temp);
495 temp = xmlGetProp(node, (const xmlChar *)"priority");
496 if(temp != NULL)
498 item->priority = atoi((gchar *)temp);
499 xmlFree(temp);
501 temp = xmlGetProp(node, (const xmlChar *)"done");
502 if(temp != NULL)
504 item->done = atoi((gchar *)temp);
505 xmlFree(temp);
507 temp = xmlGetProp(node, (const xmlChar *)"start_date");
508 if(temp != NULL)
510 guint64 i = g_ascii_strtoull((gchar *)temp, NULL, 0);
511 if(i > 0) item->start = g_date_new_julian(i);
512 xmlFree(temp);
514 temp = xmlGetProp(node, (const xmlChar *)"completed_date");
515 if(temp != NULL)
517 guint64 i = g_ascii_strtoull((gchar *)temp, NULL, 0);
518 if(i > 0) item->stop = g_date_new_julian(i);
519 xmlFree(temp);
522 temp = xmlGetProp(node, (const xmlChar *)"notify");
523 if(temp != NULL)
525 gint i = (int)g_ascii_strtod((gchar *)temp,NULL);
526 item->notify = (int)i;
527 xmlFree(temp);
529 temp = xmlGetProp(node, (const xmlChar *)"enddate");
530 if(temp != NULL)
532 guint64 i = g_ascii_strtoull((gchar *)temp, NULL, 0);
533 if(i > 1 && i != GTODO_NO_DUE_DATE) item->due = g_date_new_julian(i);
534 xmlFree(temp);
536 temp = xmlGetProp(node, (const xmlChar *)"endtime");
537 if(temp != NULL)
539 gint houre =0, minute = 0;
540 gint i = (int)g_ascii_strtod((gchar *)temp,NULL);
541 if(i < 0)
543 houre = -1;minute = 0;
545 else if( i > 0 && i < 1500)
547 houre = (int)i/60;
548 minute = (int)i - houre*60;
550 item->due_time[GTODO_DUE_TIME_HOURE] = houre;
551 item->due_time[GTODO_DUE_TIME_MINUTE] = minute;
552 xmlFree(temp);
554 temp = xmlGetProp(node, (const xmlChar *)"last_edited");
555 if(temp != NULL)
557 guint64 i = g_ascii_strtoull((gchar *)temp, NULL, 0);
558 item->last_edited = (GTime) i;
559 xmlFree(temp);
562 node = node->next;
564 return item;
567 /* initialise the gtodo lib */
568 int gtodo_client_check_file(GTodoClient *cl, GError **error)
570 GnomeVFSFileInfo info;
571 GnomeVFSResult result;
572 GnomeVFSResult info_result;
573 GError *tmp_error = NULL;
574 gchar *base_path = g_path_get_dirname(cl->xml_path);
575 /* check if the error is good or wrong. */
576 g_return_val_if_fail(error == NULL || *error == NULL,FALSE);
578 /* this is dirty.. needs a fix hard *
579 * The client should do this.. so this code should be considert
580 * deprecated. I left it here thinking it wouldnt hurt anybody.
583 if(base_path != NULL)
585 gnome_vfs_make_directory(base_path, 0755);
586 g_free(base_path);
589 /* Get permission of the file */
590 /* This also tell's us if it does exists */
591 info_result = gnome_vfs_get_file_info(cl->xml_path,
592 &info,
593 GNOME_VFS_FILE_INFO_DEFAULT|GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS );
595 /* If I got the info to check it out */
596 if(info_result == GNOME_VFS_OK )
598 GnomeVFSHandle *handle;
599 gchar *read_buf = NULL;
600 int perm = (info.permissions-(int)(info.permissions/65536)*65536);
601 int read = (int)(perm/256);
602 int write =(int)((perm - (int)(perm/256)*256)/128);
604 /* If I am not allowed to read the file */
605 if(read == 0)
607 /* save some more info here.. check for some logicol errors and print it. */
608 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_NO_PERMISSION,
609 _("No permission to read the file."));
610 g_propagate_error(error, tmp_error);
611 return TRUE;
613 cl->read_only = !write;
616 if((result = gnome_vfs_open(&handle,cl->xml_path, GNOME_VFS_OPEN_READ)) != GNOME_VFS_OK)
618 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GNOME_VFS,gnome_vfs_result_to_string(result));
619 g_propagate_error(error, tmp_error);
620 return TRUE;
622 read_buf = g_malloc0((info.size+1)*sizeof(char));
624 result = gnome_vfs_read(handle, read_buf, info.size,NULL);
625 if(!(result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_EOF))
627 g_free(read_buf);
628 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GNOME_VFS,gnome_vfs_result_to_string(result));
629 g_propagate_error(error, tmp_error);
630 return TRUE;
632 gnome_vfs_close(handle);
633 cl->gtodo_doc = xmlParseMemory(read_buf, info.size);
634 if(cl->gtodo_doc == NULL)
636 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_XML,_("Failed to parse xml structure"));
637 g_propagate_error(error, tmp_error);
638 if(debug) g_print("**DEBUG** failed to read the file \n");
639 return TRUE;
641 g_free(read_buf);
642 /* get root element.. this "root" is used in the while program */
643 cl->root = xmlDocGetRootElement(cl->gtodo_doc);
644 if(cl->root == NULL)
646 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_XML,_("Failed to parse xml structure"));
647 g_propagate_error(error, tmp_error);
648 if(debug)g_print("**DEBUG** failed to get root node.\n");
649 return TRUE;
651 /* check if the name of the root file is ok.. just to make sure :) */
652 if(!xmlStrEqual(cl->root->name, (const xmlChar *)"gtodo"))
654 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_XML,_("File is not a valid gtodo file"));
655 g_propagate_error(error, tmp_error);
656 return TRUE;
659 else if(info_result == GNOME_VFS_ERROR_NOT_FOUND){
660 xmlNodePtr newn;
661 if(debug) g_print("Trying to create new file\n");
662 cl->gtodo_doc = xmlNewDoc((xmlChar *)"1.0");
663 cl->root = xmlNewDocNode(cl->gtodo_doc, NULL, (xmlChar *)"gtodo", NULL);
664 xmlDocSetRootElement(cl->gtodo_doc, cl->root);
665 newn = xmlNewTextChild(cl->root, NULL, (xmlChar *)"category", NULL);
666 xmlNewProp(newn, (xmlChar *)"title", (xmlChar *)_("Personal"));
667 newn = xmlNewTextChild(cl->root, NULL, (xmlChar *)"category", NULL);
668 xmlNewProp(newn, (xmlChar *)"title", (xmlChar *)_("Business"));
669 newn = xmlNewTextChild(cl->root, NULL, (xmlChar *)"category", NULL);
670 xmlNewProp(newn, (xmlChar *)"title", (xmlChar *)_("Unfiled"));
671 if(gtodo_client_save_xml(cl, &tmp_error))
673 g_propagate_error(error, tmp_error);
674 return TRUE;
676 cl->read_only = FALSE;
678 else{
679 /* save some more info here.. check for some logicol errors and print it. */
680 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GNOME_VFS,gnome_vfs_result_to_string(info_result));
681 g_propagate_error(error, tmp_error);
682 return TRUE;
684 return FALSE;
687 /* Remove unwanted text nodes from the document */
689 static void
690 gtodo_client_cleanup_doc (GTodoClient *cl)
692 xmlNodePtr level1, next1;
693 level1 = cl->root->xmlChildrenNode;
694 while(level1 != NULL){
695 xmlNodePtr level2, next2;
696 next1 = level1->next;
698 if(xmlNodeIsText(level1)) {
699 xmlUnlinkNode(level1);
700 xmlFreeNode(level1);
701 } else {
702 level2 = level1->xmlChildrenNode;
703 while(level2 != NULL) {
704 xmlNodePtr level3, next3;
705 next2 = level2->next;
707 if(xmlNodeIsText(level2)) {
708 xmlUnlinkNode(level2);
709 xmlFreeNode(level2);
710 } else {
711 level3 = level2->xmlChildrenNode;
712 while (level3 != NULL) {
713 // xmlNodePtr level4, next4;
714 next3 = level3->next;
716 if(xmlNodeIsText(level3)) {
717 xmlUnlinkNode(level3);
718 xmlFreeNode(level3);
720 level3 = next3;
723 level2 = next2;
726 level1 = next1;
730 /* save the gtodo_Client */
732 int gtodo_client_save_xml(GTodoClient *cl, GError **error)
734 GError *tmp_error = NULL;
735 /* check if the error is good or wrong. */
736 g_return_val_if_fail(error == NULL || *error == NULL,FALSE);
738 if(debug)g_print("** DEBUG ** saving %s\n", cl->xml_path);
739 gtodo_client_cleanup_doc (cl);
740 if(gtodo_client_save_xml_to_file(cl, cl->xml_path, &tmp_error))
742 g_propagate_error(error, tmp_error);
743 return TRUE;
745 return FALSE;
749 int gtodo_client_save_xml_to_file(GTodoClient *cl, gchar *file, GError **error)
751 xmlChar *buffer;
752 GnomeVFSHandle *handle;
753 GnomeVFSResult result = 0;
754 GError *tmp_error = NULL;
755 int size;
756 /* Test if there is actually a client to save */
757 if(cl == NULL)
759 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GENERIC,_("No Gtodo Client to save.") );
760 g_propagate_error(error, tmp_error);
761 return TRUE;
763 /* dump the xml to memory */
764 /* xmlIndentTreeOutput = 1; */
765 xmlKeepBlanksDefault(0);
766 xmlDocDumpFormatMemory(cl->gtodo_doc, &buffer, &size, TRUE);
767 /* dirty trick to get the whole crap to work on ftp */
768 if(!strncmp(file, "ftp://", MIN(strlen(file),6)))
770 GnomeVFSURI *uri = gnome_vfs_uri_new(file);
771 if(uri != NULL && gnome_vfs_uri_exists(uri))
773 /* stupid hack to make everything work.. darn ftp */
774 if(debug)g_print("trying to unlink the file\n");
775 if(gnome_vfs_unlink(file) != GNOME_VFS_OK)
777 if(debug)g_print("Failed to delete\n");
778 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GENERIC,_("Failed to delete %s."),file);
779 g_propagate_error(error, tmp_error);
780 return TRUE;
782 else
784 if(debug)g_print("file unlinked\n");
787 gnome_vfs_uri_unref(uri);
790 /* open the file for writing */
791 result = gnome_vfs_create(&handle,file,GNOME_VFS_OPEN_WRITE, 0, 0644);
792 if(result != GNOME_VFS_OK)
794 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GENERIC,_("Failed to create/open file.") );
795 g_propagate_error(error, tmp_error);
796 return TRUE;
799 /* start writing */
800 result = gnome_vfs_write(handle, buffer, size, NULL);
801 if(result != GNOME_VFS_OK)
803 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GENERIC,_("Failed to write data to file.") );
804 g_propagate_error(error, tmp_error);
805 xmlFree(buffer);
806 return TRUE;
808 /* close the file connection */
809 gnome_vfs_close(handle);
811 xmlFree(buffer);
812 /* return that everything is ok */
813 return FALSE;
816 int gtodo_client_reload(GTodoClient *cl)
818 /* fixme */
819 if (cl->gtodo_doc)
820 xmlFreeDoc(cl->gtodo_doc);
821 cl->root = NULL;
822 if(gtodo_client_check_file(cl, NULL))
824 if(debug)g_print("Failed to reload the file\n");
825 return FALSE;
827 return TRUE;
830 int gtodo_client_load(GTodoClient *cl, const gchar *xml_path)
832 /* fixme */
833 if (cl->gtodo_doc)
834 xmlFreeDoc(cl->gtodo_doc);
835 cl->root = NULL;
836 if (cl->xml_path)
837 g_free (cl->xml_path);
838 cl->xml_path = g_strdup (xml_path);
839 if(gtodo_client_check_file(cl, NULL))
841 if(debug)g_print("Failed to reload the file\n");
842 return FALSE;
844 gtodo_client_set_changed_callback (cl, cl->function, cl->data);
845 if (cl->function)
846 cl->function(cl, cl->data);
847 return TRUE;
850 GTodoClient * gtodo_client_new_default(GError **error)
852 GError *tmp_error = NULL;
853 GTodoClient *cl = NULL;
854 /* check if the error is good or wrong. */
855 g_return_val_if_fail(error == NULL || *error == NULL,FALSE);
858 cl = g_malloc(sizeof(GTodoClient));
859 cl->xml_path = g_strdup_printf("file:///%s/.gtodo/todos", g_getenv("HOME"));
860 /* check, open or create the correct xml file */
861 if(gtodo_client_check_file(cl, &tmp_error))
863 g_propagate_error(error, tmp_error);
864 return NULL;
866 cl->timeout = NULL;
868 return cl;
871 GTodoClient * gtodo_client_new_from_file(char *filename, GError **error)
873 GError *tmp_error = NULL;
874 GTodoClient *cl = NULL;
875 /* check if the error is good or wrong. */
876 g_return_val_if_fail(error == NULL || *error == NULL,FALSE);
877 if(debug)g_print("Trying to create a new client %s\n", filename);
878 if(filename == NULL)
880 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_NO_FILENAME,_("No filename supplied.") );
881 g_propagate_error(error, tmp_error);
882 return NULL;
885 cl = g_malloc(sizeof(GTodoClient));
886 cl->xml_path = g_strdup(filename);
887 /* check, open or create the correct xml file */
888 if(gtodo_client_check_file(cl,&tmp_error))
890 g_propagate_error(error, tmp_error);
891 return NULL;
894 cl->timeout = NULL;
895 return cl;
898 void gtodo_client_quit(GTodoClient *cl)
900 gtodo_client_save_xml(cl,NULL);
901 g_free(cl->xml_path);
902 g_free(cl);
905 static
906 gboolean sort_category_list(GTodoCategory *a, GTodoCategory *b)
908 return a->id-b->id;
912 GTodoList * gtodo_client_get_category_list(GTodoClient *cl)
914 xmlNodePtr cur;
915 int repos = 0;
916 GTodoCategory *cat;
917 GTodoList *list = g_malloc(sizeof(GTodoList));
918 list->list = NULL;
920 cl->number_of_categories = 0;
921 cur = cl->root->xmlChildrenNode;
924 while(cur != NULL){
925 if(xmlStrEqual(cur->name, (const xmlChar *)"category")){
926 xmlChar *temp, *place;
927 int pos;
928 temp = xmlGetProp(cur, (const xmlChar *)"title");
929 place = xmlGetProp(cur, (const xmlChar *)"place");
930 if(place == NULL)
932 gchar *buf = g_strdup_printf("%i", repos);
933 xmlSetProp(cur, (const xmlChar *)"place", (xmlChar *)buf);
934 g_free(buf);
935 repos ++;
936 pos = repos;
938 else pos = atoi((gchar *)place);
939 cl->number_of_categories++;
940 cat = g_malloc(sizeof(GTodoCategory));
941 cat->name = g_strdup((gchar *)temp);
942 cat->id = pos;
943 list->list = g_list_append(list->list, cat);
944 xmlFree(temp);
945 xmlFree(place);
947 cur = cur->next;
949 /* sort the list */
950 list->list = g_list_sort(list->list, (GCompareFunc) sort_category_list);
951 /* if I passed numbers, save the file.. */
952 /* if its OK, this should be allright.. it goes horrible wrong
953 if there are items withouth a number in the same file that contain items with numbers */
954 if(repos != 0) gtodo_client_save_xml(cl,NULL);
955 if(list->list == NULL)
957 g_free(list);
958 return NULL;
960 else
962 list->first = g_list_first(list->list);
963 return list;
967 static
968 void gtodo_client_free_category_item(GTodoCategory *cat)
970 g_free(cat->name);
973 void gtodo_client_free_category_list(GTodoClient *cl, GTodoList *list)
975 if(list == NULL)
977 return;
979 g_list_foreach(list->first, (GFunc) gtodo_client_free_category_item, NULL);
980 g_list_free(list->first);
981 g_free(list);
984 /* get a glist with todo's */
985 GTodoList *gtodo_client_get_todo_item_list(GTodoClient *cl, gchar *category)
987 xmlNodePtr cur = cl->root->xmlChildrenNode;
988 GTodoList *list = g_malloc(sizeof(GTodoList));
989 list->list = NULL;
990 while (cur != NULL)
992 xmlChar *temp;
993 temp = xmlGetProp(cur, (const xmlChar *)"title");
994 if(category == NULL || xmlStrEqual(temp, (const xmlChar *)category))
996 xmlNodePtr cur1;
997 cur1= cur->xmlChildrenNode;
998 while(cur1 != NULL)
1000 if(xmlStrEqual(cur1->name, (const xmlChar *)"item"))
1002 GTodoItem *item = gtodo_client_get_todo_item_from_xml_ptr(cl,cur1);
1003 if(item != NULL)list->list = g_list_append(list->list, item);
1005 cur1 = cur1->next;
1008 xmlFree(temp);
1009 cur = cur->next;
1011 if(list->list == NULL)
1013 g_free(list);
1014 return NULL;
1016 list->first = g_list_first(list->list);
1017 return list;
1020 /* free the todo's items */
1021 void gtodo_client_free_todo_item_list(GTodoClient *cl, GTodoList *list)
1023 if(list == NULL)
1025 return;
1027 g_list_foreach(list->first, (GFunc) gtodo_todo_item_free, NULL);
1028 g_list_free(list->first);
1029 g_free(list);
1033 GTodoItem *gtodo_client_get_todo_item_from_id(GTodoClient *cl, guint32 id)
1035 xmlNodePtr node = cl->root;
1036 xmlNodePtr cur = cl->root->xmlChildrenNode;
1037 while(cur != NULL){
1038 if(xmlStrEqual(cur->name, (xmlChar *)"category")){
1039 xmlChar *temp = xmlGetProp(cur, (const xmlChar *)"title");
1041 xmlNodePtr cur1;
1042 cur1 = cur->xmlChildrenNode;
1043 while(cur1 != NULL)
1045 if(xmlStrEqual(cur1->name, (const xmlChar *)"item"))
1047 xmlNodePtr cur2;
1048 cur2 = cur1->xmlChildrenNode;
1049 while(cur2 != NULL)
1051 if(xmlStrEqual(cur2->name, (const xmlChar *)"attribute"))
1053 xmlChar *temp1 = xmlGetProp(cur2,(xmlChar *)"id");
1054 if(temp1 != NULL)
1056 if(atoi((gchar *)temp1) == id)node = cur1;
1057 xmlFree(temp1);
1060 cur2 = cur2->next;
1063 cur1 = cur1->next;
1066 xmlFree(temp);
1069 cur = cur->next;
1071 if(node == cl->root)
1073 return NULL;
1075 return gtodo_client_get_todo_item_from_xml_ptr(cl,node);
1078 gboolean gtodo_client_save_todo_item(GTodoClient *cl, GTodoItem *item)
1080 xmlNodePtr cur = cl->root->xmlChildrenNode;
1081 if(!gtodo_client_category_exists(cl, item->category))
1083 gtodo_client_category_new(cl, item->category);
1085 while (cur != NULL)
1087 xmlChar *temp2;
1088 temp2 = xmlGetProp(cur, (const xmlChar *)"title");
1089 if(xmlStrEqual(temp2, (xmlChar *)item->category))
1091 gchar *temp1;
1092 xmlNodePtr newn, newa;
1093 newn = xmlNewChild(cur, NULL, (xmlChar *)"item", NULL);
1094 /* id */
1095 newa = xmlNewChild(newn, NULL, (xmlChar *)"attribute", NULL);
1096 temp1 = g_strdup_printf("%i", item->id);
1097 xmlSetProp(newa, (xmlChar *)"id", (xmlChar *)temp1);
1098 g_free(temp1);
1099 /* priority */
1100 temp1 = g_strdup_printf("%i", item->priority);
1101 xmlSetProp(newa, (xmlChar *)"priority", (xmlChar *)temp1);
1102 g_free(temp1);
1103 /* done */
1104 temp1 = g_strdup_printf("%i", item->done);
1105 xmlSetProp(newa, (xmlChar *)"done", (xmlChar *)temp1);
1106 g_free(temp1);
1108 /* START_DATE */
1109 /* if new item .. nothing is done yet */
1110 if(item->start != NULL)
1112 guint32 julian = g_date_get_julian(item->start);
1113 temp1 = g_strdup_printf("%u", julian);
1114 xmlSetProp(newa, (xmlChar *)"start_date", (xmlChar *)temp1);
1115 g_free(temp1);
1117 /*( COMPLETED_DATE */
1118 if(item->stop != NULL && item->done)
1120 guint32 julian = g_date_get_julian(item->stop);
1121 temp1 = g_strdup_printf("%u", julian);
1122 xmlSetProp(newa, (xmlChar *)"completed_date", (xmlChar *)temp1);
1123 g_free(temp1);
1126 /* enddate (to the start date attribute) */
1127 if(item->due != NULL)
1129 guint32 julian = g_date_get_julian(item->due);
1130 temp1 = g_strdup_printf("%u", julian);
1131 xmlSetProp(newa, (xmlChar *)"enddate", (xmlChar *)temp1);
1132 g_free(temp1);
1134 /* enddate (to the start date attribute) */
1136 temp1 = g_strdup_printf("%i", (gint)item->notify);
1137 xmlSetProp(newa, (xmlChar *)"notify", (xmlChar *)temp1);
1138 g_free(temp1);
1140 /* endtime (to the start date attribute) */
1141 if(item->due != NULL)
1143 temp1 = g_strdup_printf("%i", (item->due_time[GTODO_DUE_TIME_HOURE]*60)+item->due_time[GTODO_DUE_TIME_MINUTE]);
1144 xmlSetProp(newa, (xmlChar *)"endtime", (xmlChar *)temp1);
1145 g_free(temp1);
1147 /* last edited (to the start date attribute) */
1149 temp1 = g_strdup_printf("%u", (GTime)time(NULL));
1150 xmlSetProp(newa, (xmlChar *)"last_edited", (xmlChar *)temp1);
1151 g_free(temp1);
1153 /* summary */
1154 newa = xmlNewChild(newn, NULL, (xmlChar *)"summary", (xmlChar *)item->summary);
1155 /* comment */
1156 newa = xmlNewChild(newn, NULL, (xmlChar *)"comment", (xmlChar *)item->comment);
1158 g_free(temp2);
1159 cur = cur->next;
1161 gtodo_client_save_xml(cl,NULL);
1162 return TRUE;
1165 gchar * gtodo_client_get_category_from_list(GTodoList *list)
1167 GTodoCategory * cat = list->list->data;
1168 return cat->name;
1171 gint gtodo_client_get_category_id_from_list(GTodoList *list)
1173 GTodoCategory * cat = list->list->data;
1174 return cat->id;
1177 GTodoItem *gtodo_client_get_todo_item_from_list(GTodoList *list)
1179 return list->list->data;
1181 gboolean gtodo_client_get_list_next(GTodoList *list)
1183 if(list == NULL) return FALSE;
1184 if(list->list == NULL) return FALSE;
1185 list->list = g_list_next(list->list);
1186 if(list->list == NULL) return FALSE;
1187 else return TRUE;
1190 /* You should get the todo item first.. then edit the item and pass it to this function to see it chagned*/
1191 gboolean gtodo_client_edit_todo_item(GTodoClient *cl, GTodoItem *item)
1193 if(cl == NULL || item == NULL) return FALSE;
1194 if(!gtodo_client_category_exists(cl, item->category)) return FALSE;
1195 gtodo_client_delete_todo_by_id(cl, item->id);
1196 if(!gtodo_client_save_todo_item(cl, item)) return FALSE;
1197 return TRUE;
1200 void gtodo_client_delete_todo_by_id(GTodoClient *cl, guint32 id)
1202 xmlNodePtr node = cl->root;
1203 xmlNodePtr cur = cl->root->xmlChildrenNode;
1204 while(cur != NULL){
1205 if(xmlStrEqual(cur->name, (xmlChar *)"category")){
1206 xmlChar *temp = xmlGetProp(cur, (const xmlChar *)"title");
1208 xmlNodePtr cur1;
1209 cur1 = cur->xmlChildrenNode;
1210 while(cur1 != NULL)
1212 if(xmlStrEqual(cur1->name, (const xmlChar *)"item"))
1214 xmlNodePtr cur2;
1215 cur2 = cur1->xmlChildrenNode;
1216 while(cur2 != NULL)
1218 if(xmlStrEqual(cur2->name, (const xmlChar *)"attribute"))
1220 xmlChar *temp1 = xmlGetProp(cur2,(xmlChar *)"id");
1221 if(temp1 != NULL)
1223 if(g_ascii_strtoull((gchar *)temp1,NULL,0) == id)node = cur1;
1224 xmlFree(temp1);
1227 cur2 = cur2->next;
1230 cur1 = cur1->next;
1233 xmlFree(temp);
1236 cur = cur->next;
1238 if(node == cl->root)
1240 return;
1242 xmlUnlinkNode(node);
1243 xmlFreeNode(node);
1244 gtodo_client_save_xml(cl,NULL);
1247 int check_item_changed(GnomeVFSMonitorHandle *handle, const gchar *uri, const gchar *info, GnomeVFSMonitorEventType event, GTodoClient *cl)
1249 GnomeVFSURI* vfs_uri = gnome_vfs_uri_new(uri);
1250 gboolean exists = gnome_vfs_uri_exists(vfs_uri);
1251 g_free(vfs_uri);
1252 if (!exists)
1254 return FALSE;
1256 gtodo_client_reload(cl);
1257 if(debug)g_print("**DEBUG** Item changed\n");
1258 cl->function(cl, cl->data);
1259 return TRUE;
1262 /* set the fucntion it should call when the todo database has changed */
1263 /* function should be of type void functionname(GTodoType *cl, gpointer data); */
1264 void gtodo_client_set_changed_callback(GTodoClient *cl, void *(*function)(gpointer cl, gpointer data), gpointer data)
1266 cl->function = function;
1267 gnome_vfs_monitor_add(&cl->timeout,cl->xml_path,
1268 GNOME_VFS_MONITOR_FILE,
1269 (GnomeVFSMonitorCallback)check_item_changed, cl);
1270 cl->data = data;
1273 void gtodo_client_destroy_changed_callback(GTodoClient *cl, void *(*function)(gpointer cl, gpointer data), gpointer data)
1275 cl->function = NULL;
1276 if(cl->timeout != NULL)
1278 gnome_vfs_monitor_cancel(cl->timeout);
1280 cl->data = NULL;
1283 /* returns TRUE is successfull */
1284 gboolean gtodo_client_category_edit(GTodoClient *cl, gchar *old, gchar *newn)
1286 if(cl == NULL || old == NULL || newn == NULL) return FALSE;
1287 if(gtodo_client_category_exists(cl, newn) && !gtodo_client_category_exists(cl, old)) return FALSE;
1288 else
1290 xmlNodePtr cur = cl->root->xmlChildrenNode;
1291 while(cur != NULL){
1292 if(xmlStrEqual(cur->name, (xmlChar *)"category")){
1293 xmlChar *temp = xmlGetProp(cur, (const xmlChar *)"title");
1294 if(xmlStrEqual(temp, (const xmlChar *)old))
1296 xmlSetProp(cur, (xmlChar *)"title", (xmlChar *)newn);
1297 cur = NULL;
1299 else cur = cur->next;
1300 xmlFree(temp);
1302 else cur = cur->next;
1305 gtodo_client_save_xml(cl,NULL);
1306 return TRUE;
1310 static
1311 gboolean gtodo_client_category_set_id(GTodoClient *cl, gchar *name, gint id)
1313 if(cl == NULL ||name == NULL || id == -1) return FALSE;
1314 if(!gtodo_client_category_exists(cl, name)) return FALSE;
1315 else
1317 xmlNodePtr cur = cl->root->xmlChildrenNode;
1318 while(cur != NULL){
1319 if(xmlStrEqual(cur->name, (xmlChar *)"category")){
1320 xmlChar *temp = xmlGetProp(cur, (const xmlChar *)"title");
1321 if(xmlStrEqual(temp, (const xmlChar *)name))
1323 gchar *buf = g_strdup_printf("%i", id);
1324 xmlSetProp(cur, (xmlChar *)"place", (xmlChar *)buf);
1325 g_free(buf);
1326 cur = NULL;
1328 else cur = cur->next;
1329 xmlFree(temp);
1331 else cur = cur->next;
1334 gtodo_client_save_xml(cl,NULL);
1335 return TRUE;
1338 #if 0
1339 static
1340 gchar *gtodo_client_category_get_from_id(GTodoClient *cl,gint id)
1342 gchar *ret_val = NULL;
1343 GTodoList *list = gtodo_client_get_category_list(cl);
1344 if(list != NULL)
1347 gint ref_id = gtodo_client_get_category_id_from_list(list);
1348 if(ref_id == id && ret_val == NULL) ret_val = g_strdup(gtodo_client_get_category_from_list(list));
1349 }while(gtodo_client_get_list_next(list));
1350 gtodo_client_free_category_list(cl,list);
1352 return ret_val;
1354 #endif
1356 gboolean gtodo_client_category_move_up(GTodoClient *cl, gchar *name)
1358 gint orig_id=0;
1359 gchar *above_name = NULL;
1360 if(name != NULL)
1362 GTodoList *list = gtodo_client_get_category_list(cl);
1363 if(list != NULL)
1366 gchar *name1 = gtodo_client_get_category_from_list(list);
1367 gint id = gtodo_client_get_category_id_from_list(list);
1368 if(strcmp(name1,name) == 0 && orig_id == 0)orig_id = id;
1369 }while(gtodo_client_get_list_next(list));
1371 if(orig_id == 0)
1373 gtodo_client_free_category_list(cl,list);
1374 return FALSE;
1376 gtodo_client_get_list_first(list);
1377 if(list != NULL)
1380 gchar *name1 = gtodo_client_get_category_from_list(list);
1381 gint id = gtodo_client_get_category_id_from_list(list);
1382 if(id == (orig_id -1) && above_name == NULL) above_name = g_strdup(name1);
1383 }while(gtodo_client_get_list_next(list));
1384 gtodo_client_free_category_list(cl,list);
1386 if(above_name == NULL) return FALSE;
1387 gtodo_client_category_set_id(cl, name, (orig_id -1));
1388 gtodo_client_category_set_id(cl, above_name, (orig_id));
1389 g_free(above_name);
1390 return TRUE;
1392 return FALSE;
1395 gboolean gtodo_client_category_move_down(GTodoClient *cl, gchar *name)
1397 gint orig_id=0;
1398 gchar *under_name = NULL;
1399 if(name != NULL)
1401 GTodoList *list = gtodo_client_get_category_list(cl);
1402 if(list != NULL)
1405 gchar *name1 = gtodo_client_get_category_from_list(list);
1406 gint id = gtodo_client_get_category_id_from_list(list);
1407 if(strcmp(name1,name) == 0 && orig_id == 0)orig_id = id;
1408 }while(gtodo_client_get_list_next(list));
1410 if(orig_id == (cl->number_of_categories -1))
1412 gtodo_client_free_category_list(cl,list);
1413 return FALSE;
1415 gtodo_client_get_list_first(list);
1416 if(list != NULL)
1419 gchar *name1 = gtodo_client_get_category_from_list(list);
1420 gint id = gtodo_client_get_category_id_from_list(list);
1421 if(id == (orig_id +1) && under_name == NULL) under_name = g_strdup(name1);
1422 }while(gtodo_client_get_list_next(list));
1423 gtodo_client_free_category_list(cl,list);
1425 if(under_name == NULL) return FALSE;
1426 gtodo_client_category_set_id(cl, name, (orig_id +1));
1427 gtodo_client_category_set_id(cl, under_name, (orig_id));
1428 g_free(under_name);
1429 return TRUE;
1431 return FALSE;
1434 gboolean gtodo_client_category_exists(GTodoClient *cl, gchar *name)
1436 GTodoList *list = gtodo_client_get_category_list(cl);
1437 if(cl == NULL || name == NULL) return FALSE;
1438 if(list != NULL)
1441 if(!strcmp(name, gtodo_client_get_category_from_list(list)))
1443 gtodo_client_free_category_list(cl, list);
1444 return TRUE;
1446 }while(gtodo_client_get_list_next(list));
1448 return FALSE;
1451 gboolean gtodo_client_category_new(GTodoClient *cl, gchar *name)
1453 xmlNodePtr newn;
1454 gchar *buf = NULL;
1455 if(cl == NULL || name == NULL) return FALSE;
1456 if(gtodo_client_category_exists(cl, name)) return FALSE;
1457 newn = xmlNewTextChild(cl->root, NULL, (xmlChar *)"category", NULL);
1458 xmlNewProp(newn, (xmlChar *)"title", (xmlChar *)name);
1459 buf = g_strdup_printf("%i", cl->number_of_categories);
1460 cl->number_of_categories++;
1461 xmlNewProp(newn, (xmlChar *)"place", (xmlChar *)buf);
1462 g_free(buf);
1463 gtodo_client_save_xml(cl,NULL);
1464 return TRUE;
1467 gboolean gtodo_client_category_remove(GTodoClient *cl, gchar *name)
1469 gint id=-1;
1470 if(cl == NULL || name == NULL) return FALSE;
1471 if(!gtodo_client_category_exists(cl, name)) return FALSE;
1472 else
1474 xmlNodePtr cur = cl->root->xmlChildrenNode;
1475 /* gtodo_client_block_changed_callback(cl);
1476 */ while(cur != NULL){
1477 if(xmlStrEqual(cur->name, (xmlChar *)"category")){
1478 xmlChar *temp = xmlGetProp(cur, (const xmlChar *)"title");
1479 if(xmlStrEqual(temp, (const xmlChar *)name))
1481 xmlChar *idchar = xmlGetProp(cur, (const xmlChar *)"place");
1482 if(idchar != NULL) id = atoi((gchar *)idchar);
1483 xmlFree(idchar);
1484 xmlUnlinkNode(cur);
1485 xmlFreeNode(cur);
1486 cur = NULL;
1488 else cur = cur->next;
1489 xmlFree(temp);
1491 else cur = cur->next;
1494 gtodo_client_save_xml(cl,NULL);
1495 /* one number is removed.. now we need to renumber.. */
1496 if(id >= -1)
1498 GTodoList *list = gtodo_client_get_category_list(cl);
1499 if(list != NULL)
1502 int ref_id = gtodo_client_get_category_id_from_list(list);
1503 if(id < ref_id)
1505 gchar *name = gtodo_client_get_category_from_list(list);
1506 gtodo_client_category_set_id(cl, name, (ref_id -1));
1508 }while(gtodo_client_get_list_next(list));
1511 gtodo_client_free_category_list(cl, list);
1514 gtodo_client_save_xml(cl,NULL);
1515 /* this doesnt work.. have to adapt gtodo to do that
1516 gtodo_client_unblock_changed_callback(cl);
1518 return TRUE;
1522 void gtodo_client_block_changed_callback(GTodoClient *cl)
1524 if(cl->timeout != NULL)
1526 gnome_vfs_monitor_cancel(cl->timeout);
1528 cl->timeout = NULL;
1531 void gtodo_client_unblock_changed_callback(GTodoClient *cl)
1533 if(cl->timeout == NULL)
1535 gnome_vfs_monitor_add(&cl->timeout,cl->xml_path,
1536 GNOME_VFS_MONITOR_FILE,
1537 (GnomeVFSMonitorCallback)check_item_changed, cl);
1541 /* This function is deprecated now */
1542 void gtodo_client_reset_changed_callback(GTodoClient *cl)
1544 if(cl->timeout != NULL) return;
1547 void gtodo_client_get_list_first(GTodoList *list)
1549 list->list = list->first;
1552 /* als base niewer is dan test dan positief */
1553 long int gtodo_item_compare_latest(GTodoItem *base, GTodoItem *test)
1555 if(base == NULL || test == NULL) return 0;
1556 return base->last_edited-test->last_edited;
1559 /* make duplicate an exact copy of source */
1560 void gtodo_client_save_client_to_client(GTodoClient *source, GTodoClient *duplicate)
1562 gtodo_client_save_xml_to_file(source, duplicate->xml_path,NULL);
1563 gtodo_client_reload(duplicate);
1566 gboolean gtodo_client_get_read_only(GTodoClient *cl)
1568 if(cl == NULL) return FALSE;
1569 return cl->read_only;