Updated Spanish translation
[anjuta-git-plugin.git] / plugins / gtodo / libgtodo.c
blob5f9573cb21a745cb7b29ffe84e6cfbe993e8caa6
1 #include <glib.h>
2 #include <glib/gi18n.h>
3 #include <string.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <time.h>
8 #include <libxml/parser.h>
9 #include <libxml/tree.h>
10 #include "libgtodo.h"
11 #include <libgnomevfs/gnome-vfs.h>
13 #ifdef DEBUG
14 short int debug = 1;
15 #else
16 short int debug = 0;
17 #endif
19 typedef struct _GTodoCategory{
20 gchar *name;
21 gint id;
22 } GTodoCategory;
24 /* should not be used by the user. internal function */
25 GTodoItem * gtodo_client_get_todo_item_from_xml_ptr(GTodoClient *cl, xmlNodePtr node);
27 /* this checks if the xml backend file exists.. not to be used by the user */
28 int check_item_changed(GnomeVFSMonitorHandle *handle, const gchar *uri, const gchar *info, GnomeVFSMonitorEventType event, GTodoClient *cl);
30 int gtodo_client_check_file(GTodoClient *cl, GError **error);
33 /* Function that creates an empty todo item. WARNING Don't use this when adding a todo item to the list.*/
34 /* Use gtodo_client_create_new_todo_item instead */
35 /* 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 )*/
37 GTodoItem * gtodo_client_create_empty_todo_item(void)
39 GTodoItem *item = g_malloc(sizeof(GTodoItem));
40 if(item == NULL) return NULL;
41 item->id = 0;
42 item->notify = FALSE;
43 item->last_edited = 0;
44 item->start = NULL;
45 item->stop = NULL;
46 item->due = NULL;
47 item->done = FALSE;
48 item->category = NULL;
49 item->priority = GTODO_PRIORITY_MEDIUM;
50 item->summary = NULL;
51 item->comment = NULL;
52 item->due_time[GTODO_DUE_TIME_HOURE] = -1;
53 item->due_time[GTODO_DUE_TIME_MINUTE] = 0;
54 return item;
57 /* create a new unique todo item */
58 /* use this to add an todo item */
59 GTodoItem * gtodo_client_create_new_todo_item(GTodoClient *cl)
61 GTodoItem *item = gtodo_client_create_empty_todo_item();
62 /* give an nice "random" id */
63 item->id = (GTime)time(NULL);
64 /* set the start time */
65 item->start = g_date_new();
66 g_date_set_time(item->start, (GTime)item->id);
67 return item;
71 /* free's an GTodoItem */
72 void gtodo_todo_item_free(GTodoItem *item)
74 if(item->start != NULL) g_date_free(item->start);
75 if(item->stop != NULL) g_date_free(item->stop);
76 if(item->due != NULL) g_date_free(item->due);
77 if(item->category != NULL) g_free(item->category);
78 if(item->summary != NULL) g_free(item->summary);
79 if(item->comment != NULL) g_free(item->comment);
80 g_free(item);
84 /* get the id from an todo item in guint32 (its an GTime, but a gtime is an gint32)..*/
85 /* I made it a guint32 because there is no negative time here */
86 guint32 gtodo_todo_item_get_id(GTodoItem *item)
88 return (guint32 )item->id;
91 /* set the notification flag for this todo item. */
92 void gtodo_todo_item_set_notify(GTodoItem *item, gboolean notify)
94 item->notify = notify;
96 /* get the statis of the notification flag */
97 gboolean gtodo_todo_item_get_notify(GTodoItem *item)
99 return item->notify;
102 /* get the priority. see enumeration in libgtodo.h for possible return values */
103 int gtodo_todo_item_get_priority(GTodoItem *item)
105 return item->priority;
108 /* set the priority, for possible value's look @ enumeration in libgtodo.c */
109 void gtodo_todo_item_set_priority(GTodoItem *item, int priority)
111 item->priority = priority;
114 /* get the summary, the returned value shouldnt be freed.*/
115 /* I return an empty string when there is no value. I am afraid this is wrong now */
117 char *gtodo_todo_item_get_summary(GTodoItem *item)
119 if(item->summary == NULL) return "";
120 return item->summary;
123 /* set the summary, also setting to NULL, or changing is allowed */
124 void gtodo_todo_item_set_summary(GTodoItem *item, gchar *summary)
126 if(summary == NULL)
128 if(item->summary != NULL) g_free(item->summary);
129 item->summary = NULL;
131 else
133 GString *string;
134 int i;
135 string = g_string_new(summary);
136 for(i=0;i < string->len;i++)
138 if(string->str[i] == '&')
140 g_string_insert(string, i+1, "amp;");
143 if(item->summary != NULL) g_free(item->summary);
144 item->summary = string->str;
145 g_string_free(string,FALSE);
149 /* get the category, the returned value shouldnt be freeed.*/
150 char *gtodo_todo_item_get_category(GTodoItem *item)
152 return item->category;
155 /* set the category or changing is allowed */
156 /* FIXME if category exists, if not.. create it. */
157 void gtodo_todo_item_set_category(GTodoItem *item, gchar *category)
159 if(category == NULL) return;
160 /* setting to NULL is bad.. because the GTodoItem is invalid then */
161 /* {
162 if(item->category != NULL) g_free(item->category);
163 item->category = NULL;
165 */ else
167 if(item->category != NULL) g_free(item->category);
168 item->category = g_strdup(category);
172 /* get the comment, this can be a multi line string */
173 char *gtodo_todo_item_get_comment(GTodoItem *item)
175 if(item->comment == NULL) return "";
176 return item->comment;
179 /* set the comment, setting to NULL is allowed, or changing */
180 void gtodo_todo_item_set_comment(GTodoItem *item, gchar *comment)
182 if(comment == NULL)
184 if(item->comment != NULL) g_free(item->comment);
185 item->comment = NULL;
187 else{
188 GString *string;
189 int i;
190 string = g_string_new(comment);
191 for(i=0;i < string->len;i++)
193 if(string->str[i] == '&')
195 g_string_insert(string, i+1, "amp;");
198 if(item->comment != NULL) g_free(item->comment);
199 item->comment = string->str;
200 g_string_free(string, FALSE);
204 /*get/set done */
205 gboolean gtodo_todo_item_get_done(GTodoItem *item)
207 return item->done;
210 void gtodo_todo_item_set_done(GTodoItem *item, gboolean done)
212 /* if the item is set done, set done date aswell, useless to have the user set it twice */
213 if(done == TRUE) gtodo_todo_item_set_stop_date_today(item);
214 item->done = done;
217 /* > 0 allready due */
218 /* 0 due today */
219 /* <0 due in future */
220 /* GTODO_NO_DUE_DATE = no due date */
221 gint32 gtodo_todo_item_check_due(GTodoItem *item)
223 GDate *today;
224 int i;
225 if(item->due == NULL) return GTODO_NO_DUE_DATE;
226 today = g_date_new();
227 g_date_set_time(today, time(NULL));
228 i = g_date_days_between(item->due,today);
229 g_date_free(today);
230 return i;
232 /*returns the time in minutes that is still left.. it will return 0 when there is nothing left
233 ofit isnt today. */
235 int gtodo_todo_item_check_due_time_minutes_left(GTodoItem *item)
237 struct tm *lctime;
238 time_t now;
239 if(gtodo_todo_item_check_due(item) != 0) return 0;
240 now = time(NULL);
241 lctime = localtime(&now);
242 if(lctime == NULL) return 0;
243 if(item->due_time[GTODO_DUE_TIME_HOURE] == -1 && item->due_time[GTODO_DUE_TIME_MINUTE] == 0) return 3000;
244 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]));
247 /* get the last_edited date in severall format's */
248 /* return an julian date ... -1 = no date set */
249 guint32 gtodo_todo_item_get_last_edited_date_as_julian(GTodoItem *item)
251 if(item->last_edited == 0 ) return 1;
252 else
254 GDate *date = g_date_new();
255 guint32 julian=1;
256 g_date_set_time(date, item->last_edited);
257 julian = g_date_get_julian(date);
258 g_date_free(date);
259 return julian;
262 /* return the houre of the due time */
263 gint gtodo_todo_item_get_due_time_houre(GTodoItem *item)
265 return item->due_time[GTODO_DUE_TIME_HOURE];
267 /* return the houre of the due time */
268 gint gtodo_todo_item_get_due_time_minute(GTodoItem *item)
270 return item->due_time[GTODO_DUE_TIME_MINUTE];
272 /* return the houre of the due time */
273 gint gtodo_todo_item_set_due_time_minute(GTodoItem *item, gint minute)
275 if(minute < 0 && minute >=60 ) return FALSE;
276 else item->due_time[GTODO_DUE_TIME_MINUTE] = minute;
277 return TRUE;
279 /* return the houre of the due time */
280 gint gtodo_todo_item_set_due_time_houre(GTodoItem *item, gint houre)
282 if(houre < -1 && houre >= 24 ) return FALSE;
283 else item->due_time[GTODO_DUE_TIME_HOURE] = houre;
284 return TRUE;
286 /* get the start date in severall format's */
287 /* return an julian date ... -1 = no date set */
288 guint32 gtodo_todo_item_get_start_date_as_julian(GTodoItem *item)
290 if(item->start == NULL || !g_date_valid(item->start)) return 1;
291 else
293 if(!g_date_valid_julian(g_date_get_julian(item->start))) return 1;
294 return g_date_get_julian(item->start);
297 /* set start date returns false when not able to set */
298 gboolean gtodo_todo_item_set_start_date_as_julian(GTodoItem *item, guint32 julian)
300 if(!g_date_valid_julian(julian)) return FALSE;
301 if(item->start == NULL) item->start = g_date_new_julian(julian);
302 else g_date_set_julian(item->start, julian);
303 return TRUE;
307 /* get localized string.. this needs to be freed! */
308 gchar *gtodo_todo_item_get_start_date_as_string(GTodoItem *item)
310 gchar *buffer = g_malloc(sizeof(gchar)*64);
311 memset(buffer,'\0', 64*sizeof(gchar));
312 if(item == NULL || item->start == NULL)
314 g_free(buffer);
315 return NULL;
317 if(!g_date_valid(item->start))
319 g_free(buffer);
320 return NULL;
322 if(g_date_strftime(buffer, 64*sizeof(gchar), "%d %b %G", item->start) == 0)
324 g_free(buffer);
325 return NULL;
327 return buffer;
330 /* get the stop date in severall format's */
331 /* return an julian date ... 1 = no date set */
332 guint32 gtodo_todo_item_get_stop_date_as_julian(GTodoItem *item)
334 if(item->stop == NULL || !g_date_valid(item->stop)) return 1;
335 else
337 if(!g_date_valid_julian(g_date_get_julian(item->stop))) return 1;
338 return g_date_get_julian(item->stop);
342 /* set stop date returns false when not able to set */
343 gboolean gtodo_todo_item_set_stop_date_as_julian(GTodoItem *item, guint32 julian)
345 if(!g_date_valid_julian(julian)) return FALSE;
346 if(item->stop == NULL) item->stop = g_date_new_julian(julian);
347 else g_date_set_julian(item->stop, julian);
348 return TRUE;
350 gboolean gtodo_todo_item_set_stop_date_today(GTodoItem *item)
352 if(item == NULL) return FALSE;
353 if(item->stop == NULL) item->stop = g_date_new();
354 g_date_set_time(item->stop, time(NULL));
355 return TRUE;
357 /* get localized string.. this needs to be freed! */
358 gchar *gtodo_todo_item_get_stop_date_as_string(GTodoItem *item)
360 gchar *buffer = g_malloc(sizeof(gchar)*64);
361 memset(buffer, '\0', 64*sizeof(gchar));
362 if(item == NULL || item->stop == NULL)
364 g_free(buffer);
365 return NULL;
367 if(!g_date_valid(item->stop))
369 g_free(buffer);
370 return NULL;
372 if(g_date_strftime(buffer, 64*sizeof(gchar), "%d %b %G", item->stop) == 0)
374 g_free(buffer);
375 return NULL;
377 return buffer;
379 /* get the due date in severall format's */
380 /* return an julian date ... 1 = no date set */
381 guint32 gtodo_todo_item_get_due_date_as_julian(GTodoItem *item)
383 if(item->due == NULL || !g_date_valid(item->due))
385 return GTODO_NO_DUE_DATE;
387 else
389 if(!g_date_valid_julian(g_date_get_julian(item->due))) return GTODO_NO_DUE_DATE;
390 return g_date_get_julian(item->due);
394 /* set due date returns false when not able to set */
395 gboolean gtodo_todo_item_set_due_date_as_julian(GTodoItem *item, guint32 julian)
397 if(julian == GTODO_NO_DUE_DATE)
399 if(item->due != NULL)
401 g_date_free(item->due);
402 item->due = NULL;
405 if(!g_date_valid_julian((guint32)julian)) return FALSE;
406 if(item->due == NULL) item->due = g_date_new_julian((guint32)julian);
407 else g_date_set_julian(item->due, (guint32)julian);
408 return TRUE;
411 GDate * gtodo_todo_item_get_due_date(GTodoItem *item)
413 if(item == NULL || item->due == NULL) return NULL;
414 if(!g_date_valid(item->due)) return NULL;
415 return item->due;
418 /* get localized string.. this needs to be freed! */
419 gchar *gtodo_todo_item_get_due_date_as_string(GTodoItem *item)
421 gchar *buffer = g_malloc(sizeof(gchar)*64);
422 memset(buffer, '\0', 64*sizeof(gchar));
423 if(item == NULL || item->due == NULL)
425 g_free(buffer);
426 return NULL;
428 if(!g_date_valid(item->due))
430 g_free(buffer);
431 return NULL;
433 if(g_date_strftime(buffer, 64*sizeof(gchar), "%d %b %G", item->due) == 0)
435 g_free(buffer);
436 return NULL;
438 return buffer;
441 /* should not be used by the user. internal function */
442 GTodoItem * gtodo_client_get_todo_item_from_xml_ptr(GTodoClient *cl, xmlNodePtr node)
444 GTodoItem *item =NULL;
445 xmlChar *category;
446 if(node == NULL) return NULL;
447 category = xmlGetProp(node->parent, (const xmlChar *)"title");
448 node = node->xmlChildrenNode;
449 item = gtodo_client_create_empty_todo_item();
450 gtodo_todo_item_set_category(item, (gchar *)category);
451 xmlFree(category);
452 while(node != NULL)
454 if(xmlStrEqual(node->name, (const xmlChar *)"comment"))
456 xmlChar *temp;
457 temp = xmlNodeGetContent(node);
458 if(temp != NULL)
460 item->comment = g_strdup((gchar *)temp);
461 xmlFree(temp);
464 else if(xmlStrEqual(node->name, (const xmlChar *)"summary"))
466 xmlChar *temp;
467 temp = xmlNodeGetContent(node);
468 if(temp != NULL)
470 item->summary = g_strdup((gchar *)temp);
471 xmlFree(temp);
474 else if(xmlStrEqual(node->name, (const xmlChar *)"attribute"))
476 xmlChar *temp;
477 temp = xmlGetProp(node, (const xmlChar *)"id");
478 if(temp != NULL)
480 item->id = g_ascii_strtoull((gchar *)temp, NULL,0);
481 xmlFree(temp);
483 temp = xmlGetProp(node, (const xmlChar *)"priority");
484 if(temp != NULL)
486 item->priority = atoi((gchar *)temp);
487 xmlFree(temp);
489 temp = xmlGetProp(node, (const xmlChar *)"done");
490 if(temp != NULL)
492 item->done = atoi((gchar *)temp);
493 xmlFree(temp);
495 temp = xmlGetProp(node, (const xmlChar *)"start_date");
496 if(temp != NULL)
498 guint64 i = g_ascii_strtoull((gchar *)temp, NULL, 0);
499 if(i > 0) item->start = g_date_new_julian(i);
500 xmlFree(temp);
502 temp = xmlGetProp(node, (const xmlChar *)"completed_date");
503 if(temp != NULL)
505 guint64 i = g_ascii_strtoull((gchar *)temp, NULL, 0);
506 if(i > 0) item->stop = g_date_new_julian(i);
507 xmlFree(temp);
510 temp = xmlGetProp(node, (const xmlChar *)"notify");
511 if(temp != NULL)
513 gint i = (int)g_ascii_strtod((gchar *)temp,NULL);
514 item->notify = (int)i;
515 xmlFree(temp);
517 temp = xmlGetProp(node, (const xmlChar *)"enddate");
518 if(temp != NULL)
520 guint64 i = g_ascii_strtoull((gchar *)temp, NULL, 0);
521 if(i > 1 && i != GTODO_NO_DUE_DATE) item->due = g_date_new_julian(i);
522 xmlFree(temp);
524 temp = xmlGetProp(node, (const xmlChar *)"endtime");
525 if(temp != NULL)
527 gint houre =0, minute = 0;
528 gint i = (int)g_ascii_strtod((gchar *)temp,NULL);
529 if(i < 0)
531 houre = -1;minute = 0;
533 else if( i > 0 && i < 1500)
535 houre = (int)i/60;
536 minute = (int)i - houre*60;
538 item->due_time[GTODO_DUE_TIME_HOURE] = houre;
539 item->due_time[GTODO_DUE_TIME_MINUTE] = minute;
540 xmlFree(temp);
542 temp = xmlGetProp(node, (const xmlChar *)"last_edited");
543 if(temp != NULL)
545 guint64 i = g_ascii_strtoull((gchar *)temp, NULL, 0);
546 item->last_edited = (GTime) i;
547 xmlFree(temp);
550 node = node->next;
552 return item;
555 /* initialise the gtodo lib */
556 int gtodo_client_check_file(GTodoClient *cl, GError **error)
558 GnomeVFSFileInfo info;
559 GnomeVFSResult result;
560 GnomeVFSResult info_result;
561 GError *tmp_error = NULL;
562 gchar *base_path = g_path_get_dirname(cl->xml_path);
563 /* check if the error is good or wrong. */
564 g_return_val_if_fail(error == NULL || *error == NULL,FALSE);
566 /* this is dirty.. needs a fix hard *
567 * The client should do this.. so this code should be considert
568 * deprecated. I left it here thinking it wouldnt hurt anybody.
571 if(base_path != NULL)
573 gnome_vfs_make_directory(base_path, 0755);
574 g_free(base_path);
577 /* Get permission of the file */
578 /* This also tell's us if it does exists */
579 info_result = gnome_vfs_get_file_info(cl->xml_path,
580 &info,
581 GNOME_VFS_FILE_INFO_DEFAULT|GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS );
583 /* If I got the info to check it out */
584 if(info_result == GNOME_VFS_OK )
586 GnomeVFSHandle *handle;
587 gchar *read_buf = NULL;
588 int perm = (info.permissions-(int)(info.permissions/65536)*65536);
589 int read = (int)(perm/256);
590 int write =(int)((perm - (int)(perm/256)*256)/128);
592 /* If I am not allowed to read the file */
593 if(read == 0)
595 /* save some more info here.. check for some logicol errors and print it. */
596 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_NO_PERMISSION,
597 _("No permission to read the file."));
598 g_propagate_error(error, tmp_error);
599 return TRUE;
601 cl->read_only = !write;
604 if((result = gnome_vfs_open(&handle,cl->xml_path, GNOME_VFS_OPEN_READ)) != GNOME_VFS_OK)
606 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GNOME_VFS,gnome_vfs_result_to_string(result));
607 g_propagate_error(error, tmp_error);
608 return TRUE;
610 read_buf = g_malloc0((info.size+1)*sizeof(char));
612 result = gnome_vfs_read(handle, read_buf, info.size,NULL);
613 if(!(result == GNOME_VFS_OK || result == GNOME_VFS_ERROR_EOF))
615 g_free(read_buf);
616 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GNOME_VFS,gnome_vfs_result_to_string(result));
617 g_propagate_error(error, tmp_error);
618 return TRUE;
620 gnome_vfs_close(handle);
621 cl->gtodo_doc = xmlParseMemory(read_buf, info.size);
622 if(cl->gtodo_doc == NULL)
624 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_XML,_("Failed to parse xml structure"));
625 g_propagate_error(error, tmp_error);
626 if(debug) g_print("**DEBUG** failed to read the file \n");
627 return TRUE;
629 g_free(read_buf);
630 /* get root element.. this "root" is used in the while program */
631 cl->root = xmlDocGetRootElement(cl->gtodo_doc);
632 if(cl->root == NULL)
634 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_XML,_("Failed to parse xml structure"));
635 g_propagate_error(error, tmp_error);
636 if(debug)g_print("**DEBUG** failed to get root node.\n");
637 return TRUE;
639 /* check if the name of the root file is ok.. just to make sure :) */
640 if(!xmlStrEqual(cl->root->name, (const xmlChar *)"gtodo"))
642 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_XML,_("File is not a valid gtodo file"));
643 g_propagate_error(error, tmp_error);
644 return TRUE;
647 else if(info_result == GNOME_VFS_ERROR_NOT_FOUND){
648 xmlNodePtr newn;
649 if(debug) g_print("Trying to create new file\n");
650 cl->gtodo_doc = xmlNewDoc((xmlChar *)"1.0");
651 cl->root = xmlNewDocNode(cl->gtodo_doc, NULL, (xmlChar *)"gtodo", NULL);
652 xmlDocSetRootElement(cl->gtodo_doc, cl->root);
653 newn = xmlNewTextChild(cl->root, NULL, (xmlChar *)"category", NULL);
654 xmlNewProp(newn, (xmlChar *)"title", (xmlChar *)_("Personal"));
655 newn = xmlNewTextChild(cl->root, NULL, (xmlChar *)"category", NULL);
656 xmlNewProp(newn, (xmlChar *)"title", (xmlChar *)_("Business"));
657 newn = xmlNewTextChild(cl->root, NULL, (xmlChar *)"category", NULL);
658 xmlNewProp(newn, (xmlChar *)"title", (xmlChar *)_("Unfiled"));
659 if(gtodo_client_save_xml(cl, &tmp_error))
661 g_propagate_error(error, tmp_error);
662 return TRUE;
664 cl->read_only = FALSE;
666 else{
667 /* save some more info here.. check for some logicol errors and print it. */
668 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GNOME_VFS,gnome_vfs_result_to_string(info_result));
669 g_propagate_error(error, tmp_error);
670 return TRUE;
672 return FALSE;
675 /* Remove unwanted text nodes from the document */
677 static void
678 gtodo_client_cleanup_doc (GTodoClient *cl)
680 xmlNodePtr level1, next1;
681 level1 = cl->root->xmlChildrenNode;
682 while(level1 != NULL){
683 xmlNodePtr level2, next2;
684 next1 = level1->next;
686 if(xmlNodeIsText(level1)) {
687 xmlUnlinkNode(level1);
688 xmlFreeNode(level1);
689 } else {
690 level2 = level1->xmlChildrenNode;
691 while(level2 != NULL) {
692 xmlNodePtr level3, next3;
693 next2 = level2->next;
695 if(xmlNodeIsText(level2)) {
696 xmlUnlinkNode(level2);
697 xmlFreeNode(level2);
698 } else {
699 level3 = level2->xmlChildrenNode;
700 while (level3 != NULL) {
701 // xmlNodePtr level4, next4;
702 next3 = level3->next;
704 if(xmlNodeIsText(level3)) {
705 xmlUnlinkNode(level3);
706 xmlFreeNode(level3);
708 level3 = next3;
711 level2 = next2;
714 level1 = next1;
718 /* save the gtodo_Client */
720 int gtodo_client_save_xml(GTodoClient *cl, GError **error)
722 GError *tmp_error = NULL;
723 /* check if the error is good or wrong. */
724 g_return_val_if_fail(error == NULL || *error == NULL,FALSE);
726 if(debug)g_print("** DEBUG ** saving %s\n", cl->xml_path);
727 gtodo_client_cleanup_doc (cl);
728 if(gtodo_client_save_xml_to_file(cl, cl->xml_path, &tmp_error))
730 g_propagate_error(error, tmp_error);
731 return TRUE;
733 return FALSE;
737 int gtodo_client_save_xml_to_file(GTodoClient *cl, gchar *file, GError **error)
739 xmlChar *buffer;
740 GnomeVFSHandle *handle;
741 GnomeVFSResult result = 0;
742 GError *tmp_error = NULL;
743 int size;
744 /* Test if there is actually a client to save */
745 if(cl == NULL)
747 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GENERIC,_("No Gtodo Client to save.") );
748 g_propagate_error(error, tmp_error);
749 return TRUE;
751 /* dump the xml to memory */
752 /* xmlIndentTreeOutput = 1; */
753 xmlKeepBlanksDefault(0);
754 xmlDocDumpFormatMemory(cl->gtodo_doc, &buffer, &size, TRUE);
755 /* dirty trick to get the whole crap to work on ftp */
756 if(!strncmp(file, "ftp://", MIN(strlen(file),6)))
758 GnomeVFSURI *uri = gnome_vfs_uri_new(file);
759 if(uri != NULL && gnome_vfs_uri_exists(uri))
761 /* stupid hack to make everything work.. darn ftp */
762 if(debug)g_print("trying to unlink the file\n");
763 if(gnome_vfs_unlink(file) != GNOME_VFS_OK)
765 if(debug)g_print("Failed to delete\n");
766 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GENERIC,_("Failed to delete %s."),file);
767 g_propagate_error(error, tmp_error);
768 return TRUE;
770 else
772 if(debug)g_print("file unlinked\n");
775 gnome_vfs_uri_unref(uri);
778 /* open the file for writing */
779 result = gnome_vfs_create(&handle,file,GNOME_VFS_OPEN_WRITE, 0, 0644);
780 if(result != GNOME_VFS_OK)
782 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GENERIC,_("Failed to create/open file.") );
783 g_propagate_error(error, tmp_error);
784 return TRUE;
787 /* start writing */
788 result = gnome_vfs_write(handle, buffer, size, NULL);
789 if(result != GNOME_VFS_OK)
791 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_GENERIC,_("Failed to write data to file.") );
792 g_propagate_error(error, tmp_error);
793 xmlFree(buffer);
794 return TRUE;
796 /* close the file connection */
797 gnome_vfs_close(handle);
799 xmlFree(buffer);
800 /* return that everything is ok */
801 return FALSE;
804 int gtodo_client_reload(GTodoClient *cl)
806 /* fixme */
807 if (cl->gtodo_doc)
808 xmlFreeDoc(cl->gtodo_doc);
809 cl->root = NULL;
810 if(gtodo_client_check_file(cl, NULL))
812 if(debug)g_print("Failed to reload the file\n");
813 return FALSE;
815 return TRUE;
818 int gtodo_client_load(GTodoClient *cl, const gchar *xml_path)
820 /* fixme */
821 if (cl->gtodo_doc)
822 xmlFreeDoc(cl->gtodo_doc);
823 cl->root = NULL;
824 if (cl->xml_path)
825 g_free (cl->xml_path);
826 cl->xml_path = g_strdup (xml_path);
827 if(gtodo_client_check_file(cl, NULL))
829 if(debug)g_print("Failed to reload the file\n");
830 return FALSE;
832 gtodo_client_set_changed_callback (cl, cl->function, cl->data);
833 if (cl->function)
834 cl->function(cl, cl->data);
835 return TRUE;
838 GTodoClient * gtodo_client_new_default(GError **error)
840 GError *tmp_error = NULL;
841 GTodoClient *cl = NULL;
842 /* check if the error is good or wrong. */
843 g_return_val_if_fail(error == NULL || *error == NULL,FALSE);
846 cl = g_malloc(sizeof(GTodoClient));
847 cl->xml_path = g_strdup_printf("file:///%s/.gtodo/todos", g_getenv("HOME"));
848 /* check, open or create the correct xml file */
849 if(gtodo_client_check_file(cl, &tmp_error))
851 g_propagate_error(error, tmp_error);
852 return NULL;
854 cl->timeout = NULL;
856 return cl;
859 GTodoClient * gtodo_client_new_from_file(char *filename, GError **error)
861 GError *tmp_error = NULL;
862 GTodoClient *cl = NULL;
863 /* check if the error is good or wrong. */
864 g_return_val_if_fail(error == NULL || *error == NULL,FALSE);
865 if(debug)g_print("Trying to create a new client %s\n", filename);
866 if(filename == NULL)
868 g_set_error(&tmp_error,LIBGTODO_ERROR,LIBGTODO_ERROR_NO_FILENAME,_("No filename supplied.") );
869 g_propagate_error(error, tmp_error);
870 return NULL;
873 cl = g_malloc(sizeof(GTodoClient));
874 cl->xml_path = g_strdup(filename);
875 /* check, open or create the correct xml file */
876 if(gtodo_client_check_file(cl,&tmp_error))
878 g_propagate_error(error, tmp_error);
879 return NULL;
882 cl->timeout = NULL;
883 return cl;
886 void gtodo_client_quit(GTodoClient *cl)
888 gtodo_client_save_xml(cl,NULL);
889 g_free(cl->xml_path);
890 g_free(cl);
893 static
894 gboolean sort_category_list(GTodoCategory *a, GTodoCategory *b)
896 return a->id-b->id;
900 GTodoList * gtodo_client_get_category_list(GTodoClient *cl)
902 xmlNodePtr cur;
903 int repos = 0;
904 GTodoCategory *cat;
905 GTodoList *list = g_malloc(sizeof(GTodoList));
906 list->list = NULL;
908 cl->number_of_categories = 0;
909 cur = cl->root->xmlChildrenNode;
912 while(cur != NULL){
913 if(xmlStrEqual(cur->name, (const xmlChar *)"category")){
914 xmlChar *temp, *place;
915 int pos;
916 temp = xmlGetProp(cur, (const xmlChar *)"title");
917 place = xmlGetProp(cur, (const xmlChar *)"place");
918 if(place == NULL)
920 gchar *buf = g_strdup_printf("%i", repos);
921 xmlSetProp(cur, (const xmlChar *)"place", (xmlChar *)buf);
922 g_free(buf);
923 repos ++;
924 pos = repos;
926 else pos = atoi((gchar *)place);
927 cl->number_of_categories++;
928 cat = g_malloc(sizeof(GTodoCategory));
929 cat->name = g_strdup((gchar *)temp);
930 cat->id = pos;
931 list->list = g_list_append(list->list, cat);
932 xmlFree(temp);
933 xmlFree(place);
935 cur = cur->next;
937 /* sort the list */
938 list->list = g_list_sort(list->list, (GCompareFunc) sort_category_list);
939 /* if I passed numbers, save the file.. */
940 /* if its OK, this should be allright.. it goes horrible wrong
941 if there are items withouth a number in the same file that contain items with numbers */
942 if(repos != 0) gtodo_client_save_xml(cl,NULL);
943 if(list->list == NULL)
945 g_free(list);
946 return NULL;
948 else
950 list->first = g_list_first(list->list);
951 return list;
955 static
956 void gtodo_client_free_category_item(GTodoCategory *cat)
958 g_free(cat->name);
961 void gtodo_client_free_category_list(GTodoClient *cl, GTodoList *list)
963 if(list == NULL)
965 return;
967 g_list_foreach(list->first, (GFunc) gtodo_client_free_category_item, NULL);
968 g_list_free(list->first);
969 g_free(list);
972 /* get a glist with todo's */
973 GTodoList *gtodo_client_get_todo_item_list(GTodoClient *cl, gchar *category)
975 xmlNodePtr cur = cl->root->xmlChildrenNode;
976 GTodoList *list = g_malloc(sizeof(GTodoList));
977 list->list = NULL;
978 while (cur != NULL)
980 xmlChar *temp;
981 temp = xmlGetProp(cur, (const xmlChar *)"title");
982 if(category == NULL || xmlStrEqual(temp, (const xmlChar *)category))
984 xmlNodePtr cur1;
985 cur1= cur->xmlChildrenNode;
986 while(cur1 != NULL)
988 if(xmlStrEqual(cur1->name, (const xmlChar *)"item"))
990 GTodoItem *item = gtodo_client_get_todo_item_from_xml_ptr(cl,cur1);
991 if(item != NULL)list->list = g_list_append(list->list, item);
993 cur1 = cur1->next;
996 xmlFree(temp);
997 cur = cur->next;
999 if(list->list == NULL)
1001 g_free(list);
1002 return NULL;
1004 list->first = g_list_first(list->list);
1005 return list;
1008 /* free the todo's items */
1009 void gtodo_client_free_todo_item_list(GTodoClient *cl, GTodoList *list)
1011 if(list == NULL)
1013 return;
1015 g_list_foreach(list->first, (GFunc) gtodo_todo_item_free, NULL);
1016 g_list_free(list->first);
1017 g_free(list);
1021 GTodoItem *gtodo_client_get_todo_item_from_id(GTodoClient *cl, guint32 id)
1023 xmlNodePtr node = cl->root;
1024 xmlNodePtr cur = cl->root->xmlChildrenNode;
1025 while(cur != NULL){
1026 if(xmlStrEqual(cur->name, (xmlChar *)"category")){
1027 xmlChar *temp = xmlGetProp(cur, (const xmlChar *)"title");
1029 xmlNodePtr cur1;
1030 cur1 = cur->xmlChildrenNode;
1031 while(cur1 != NULL)
1033 if(xmlStrEqual(cur1->name, (const xmlChar *)"item"))
1035 xmlNodePtr cur2;
1036 cur2 = cur1->xmlChildrenNode;
1037 while(cur2 != NULL)
1039 if(xmlStrEqual(cur2->name, (const xmlChar *)"attribute"))
1041 xmlChar *temp1 = xmlGetProp(cur2,(xmlChar *)"id");
1042 if(temp1 != NULL)
1044 if(atoi((gchar *)temp1) == id)node = cur1;
1045 xmlFree(temp1);
1048 cur2 = cur2->next;
1051 cur1 = cur1->next;
1054 xmlFree(temp);
1057 cur = cur->next;
1059 if(node == cl->root)
1061 return NULL;
1063 return gtodo_client_get_todo_item_from_xml_ptr(cl,node);
1066 gboolean gtodo_client_save_todo_item(GTodoClient *cl, GTodoItem *item)
1068 xmlNodePtr cur = cl->root->xmlChildrenNode;
1069 if(!gtodo_client_category_exists(cl, item->category))
1071 gtodo_client_category_new(cl, item->category);
1073 while (cur != NULL)
1075 xmlChar *temp2;
1076 temp2 = xmlGetProp(cur, (const xmlChar *)"title");
1077 if(xmlStrEqual(temp2, (xmlChar *)item->category))
1079 gchar *temp1;
1080 xmlNodePtr newn, newa;
1081 newn = xmlNewChild(cur, NULL, (xmlChar *)"item", NULL);
1082 /* id */
1083 newa = xmlNewChild(newn, NULL, (xmlChar *)"attribute", NULL);
1084 temp1 = g_strdup_printf("%i", item->id);
1085 xmlSetProp(newa, (xmlChar *)"id", (xmlChar *)temp1);
1086 g_free(temp1);
1087 /* priority */
1088 temp1 = g_strdup_printf("%i", item->priority);
1089 xmlSetProp(newa, (xmlChar *)"priority", (xmlChar *)temp1);
1090 g_free(temp1);
1091 /* done */
1092 temp1 = g_strdup_printf("%i", item->done);
1093 xmlSetProp(newa, (xmlChar *)"done", (xmlChar *)temp1);
1094 g_free(temp1);
1096 /* START_DATE */
1097 /* if new item .. nothing is done yet */
1098 if(item->start != NULL)
1100 guint32 julian = g_date_get_julian(item->start);
1101 temp1 = g_strdup_printf("%u", julian);
1102 xmlSetProp(newa, (xmlChar *)"start_date", (xmlChar *)temp1);
1103 g_free(temp1);
1105 /*( COMPLETED_DATE */
1106 if(item->stop != NULL && item->done)
1108 guint32 julian = g_date_get_julian(item->stop);
1109 temp1 = g_strdup_printf("%u", julian);
1110 xmlSetProp(newa, (xmlChar *)"completed_date", (xmlChar *)temp1);
1111 g_free(temp1);
1114 /* enddate (to the start date attribute) */
1115 if(item->due != NULL)
1117 guint32 julian = g_date_get_julian(item->due);
1118 temp1 = g_strdup_printf("%u", julian);
1119 xmlSetProp(newa, (xmlChar *)"enddate", (xmlChar *)temp1);
1120 g_free(temp1);
1122 /* enddate (to the start date attribute) */
1124 temp1 = g_strdup_printf("%i", (gint)item->notify);
1125 xmlSetProp(newa, (xmlChar *)"notify", (xmlChar *)temp1);
1126 g_free(temp1);
1128 /* endtime (to the start date attribute) */
1129 if(item->due != NULL)
1131 temp1 = g_strdup_printf("%i", (item->due_time[GTODO_DUE_TIME_HOURE]*60)+item->due_time[GTODO_DUE_TIME_MINUTE]);
1132 xmlSetProp(newa, (xmlChar *)"endtime", (xmlChar *)temp1);
1133 g_free(temp1);
1135 /* last edited (to the start date attribute) */
1137 temp1 = g_strdup_printf("%u", (GTime)time(NULL));
1138 xmlSetProp(newa, (xmlChar *)"last_edited", (xmlChar *)temp1);
1139 g_free(temp1);
1141 /* summary */
1142 newa = xmlNewChild(newn, NULL, (xmlChar *)"summary", (xmlChar *)item->summary);
1143 /* comment */
1144 newa = xmlNewChild(newn, NULL, (xmlChar *)"comment", (xmlChar *)item->comment);
1146 g_free(temp2);
1147 cur = cur->next;
1149 gtodo_client_save_xml(cl,NULL);
1150 return TRUE;
1153 gchar * gtodo_client_get_category_from_list(GTodoList *list)
1155 GTodoCategory * cat = list->list->data;
1156 return _(cat->name);
1159 gint gtodo_client_get_category_id_from_list(GTodoList *list)
1161 GTodoCategory * cat = list->list->data;
1162 return cat->id;
1165 GTodoItem *gtodo_client_get_todo_item_from_list(GTodoList *list)
1167 return list->list->data;
1169 gboolean gtodo_client_get_list_next(GTodoList *list)
1171 if(list == NULL) return FALSE;
1172 if(list->list == NULL) return FALSE;
1173 list->list = g_list_next(list->list);
1174 if(list->list == NULL) return FALSE;
1175 else return TRUE;
1178 /* You should get the todo item first.. then edit the item and pass it to this function to see it chagned*/
1179 gboolean gtodo_client_edit_todo_item(GTodoClient *cl, GTodoItem *item)
1181 if(cl == NULL || item == NULL) return FALSE;
1182 if(!gtodo_client_category_exists(cl, item->category)) return FALSE;
1183 gtodo_client_delete_todo_by_id(cl, item->id);
1184 if(!gtodo_client_save_todo_item(cl, item)) return FALSE;
1185 return TRUE;
1188 void gtodo_client_delete_todo_by_id(GTodoClient *cl, guint32 id)
1190 xmlNodePtr node = cl->root;
1191 xmlNodePtr cur = cl->root->xmlChildrenNode;
1192 while(cur != NULL){
1193 if(xmlStrEqual(cur->name, (xmlChar *)"category")){
1194 xmlChar *temp = xmlGetProp(cur, (const xmlChar *)"title");
1196 xmlNodePtr cur1;
1197 cur1 = cur->xmlChildrenNode;
1198 while(cur1 != NULL)
1200 if(xmlStrEqual(cur1->name, (const xmlChar *)"item"))
1202 xmlNodePtr cur2;
1203 cur2 = cur1->xmlChildrenNode;
1204 while(cur2 != NULL)
1206 if(xmlStrEqual(cur2->name, (const xmlChar *)"attribute"))
1208 xmlChar *temp1 = xmlGetProp(cur2,(xmlChar *)"id");
1209 if(temp1 != NULL)
1211 if(g_ascii_strtoull((gchar *)temp1,NULL,0) == id)node = cur1;
1212 xmlFree(temp1);
1215 cur2 = cur2->next;
1218 cur1 = cur1->next;
1221 xmlFree(temp);
1224 cur = cur->next;
1226 if(node == cl->root)
1228 return;
1230 xmlUnlinkNode(node);
1231 xmlFreeNode(node);
1232 gtodo_client_save_xml(cl,NULL);
1235 int check_item_changed(GnomeVFSMonitorHandle *handle, const gchar *uri, const gchar *info, GnomeVFSMonitorEventType event, GTodoClient *cl)
1237 GnomeVFSURI* vfs_uri = gnome_vfs_uri_new(uri);
1238 gboolean exists = gnome_vfs_uri_exists(vfs_uri);
1239 g_free(vfs_uri);
1240 if (!exists)
1242 return FALSE;
1244 gtodo_client_reload(cl);
1245 if(debug)g_print("**DEBUG** Item changed\n");
1246 cl->function(cl, cl->data);
1247 return TRUE;
1250 /* set the fucntion it should call when the todo database has changed */
1251 /* function should be of type void functionname(GTodoType *cl, gpointer data); */
1252 void gtodo_client_set_changed_callback(GTodoClient *cl, void *(*function)(gpointer cl, gpointer data), gpointer data)
1254 cl->function = function;
1255 gnome_vfs_monitor_add(&cl->timeout,cl->xml_path,
1256 GNOME_VFS_MONITOR_FILE,
1257 (GnomeVFSMonitorCallback)check_item_changed, cl);
1258 cl->data = data;
1261 void gtodo_client_destroy_changed_callback(GTodoClient *cl, void *(*function)(gpointer cl, gpointer data), gpointer data)
1263 cl->function = NULL;
1264 if(cl->timeout != NULL)
1266 gnome_vfs_monitor_cancel(cl->timeout);
1268 cl->data = NULL;
1271 /* returns TRUE is successfull */
1272 gboolean gtodo_client_category_edit(GTodoClient *cl, gchar *old, gchar *newn)
1274 if(cl == NULL || old == NULL || newn == NULL) return FALSE;
1275 if(gtodo_client_category_exists(cl, newn) && !gtodo_client_category_exists(cl, old)) return FALSE;
1276 else
1278 xmlNodePtr cur = cl->root->xmlChildrenNode;
1279 while(cur != NULL){
1280 if(xmlStrEqual(cur->name, (xmlChar *)"category")){
1281 xmlChar *temp = xmlGetProp(cur, (const xmlChar *)"title");
1282 if(xmlStrEqual(temp, (const xmlChar *)old))
1284 xmlSetProp(cur, (xmlChar *)"title", (xmlChar *)newn);
1285 cur = NULL;
1287 else cur = cur->next;
1288 xmlFree(temp);
1290 else cur = cur->next;
1293 gtodo_client_save_xml(cl,NULL);
1294 return TRUE;
1298 static
1299 gboolean gtodo_client_category_set_id(GTodoClient *cl, gchar *name, gint id)
1301 if(cl == NULL ||name == NULL || id == -1) return FALSE;
1302 if(!gtodo_client_category_exists(cl, name)) return FALSE;
1303 else
1305 xmlNodePtr cur = cl->root->xmlChildrenNode;
1306 while(cur != NULL){
1307 if(xmlStrEqual(cur->name, (xmlChar *)"category")){
1308 xmlChar *temp = xmlGetProp(cur, (const xmlChar *)"title");
1309 if(xmlStrEqual(temp, (const xmlChar *)name))
1311 gchar *buf = g_strdup_printf("%i", id);
1312 xmlSetProp(cur, (xmlChar *)"place", (xmlChar *)buf);
1313 g_free(buf);
1314 cur = NULL;
1316 else cur = cur->next;
1317 xmlFree(temp);
1319 else cur = cur->next;
1322 gtodo_client_save_xml(cl,NULL);
1323 return TRUE;
1326 #if 0
1327 static
1328 gchar *gtodo_client_category_get_from_id(GTodoClient *cl,gint id)
1330 gchar *ret_val = NULL;
1331 GTodoList *list = gtodo_client_get_category_list(cl);
1332 if(list != NULL)
1335 gint ref_id = gtodo_client_get_category_id_from_list(list);
1336 if(ref_id == id && ret_val == NULL) ret_val = g_strdup(gtodo_client_get_category_from_list(list));
1337 }while(gtodo_client_get_list_next(list));
1338 gtodo_client_free_category_list(cl,list);
1340 return ret_val;
1342 #endif
1344 gboolean gtodo_client_category_move_up(GTodoClient *cl, gchar *name)
1346 gint orig_id=0;
1347 gchar *above_name = NULL;
1348 if(name != NULL)
1350 GTodoList *list = gtodo_client_get_category_list(cl);
1351 if(list != NULL)
1354 gchar *name1 = gtodo_client_get_category_from_list(list);
1355 gint id = gtodo_client_get_category_id_from_list(list);
1356 if(strcmp(name1,name) == 0 && orig_id == 0)orig_id = id;
1357 }while(gtodo_client_get_list_next(list));
1359 if(orig_id == 0)
1361 gtodo_client_free_category_list(cl,list);
1362 return FALSE;
1364 gtodo_client_get_list_first(list);
1365 if(list != NULL)
1368 gchar *name1 = gtodo_client_get_category_from_list(list);
1369 gint id = gtodo_client_get_category_id_from_list(list);
1370 if(id == (orig_id -1) && above_name == NULL) above_name = g_strdup(name1);
1371 }while(gtodo_client_get_list_next(list));
1372 gtodo_client_free_category_list(cl,list);
1374 if(above_name == NULL) return FALSE;
1375 gtodo_client_category_set_id(cl, name, (orig_id -1));
1376 gtodo_client_category_set_id(cl, above_name, (orig_id));
1377 g_free(above_name);
1378 return TRUE;
1380 return FALSE;
1383 gboolean gtodo_client_category_move_down(GTodoClient *cl, gchar *name)
1385 gint orig_id=0;
1386 gchar *under_name = NULL;
1387 if(name != NULL)
1389 GTodoList *list = gtodo_client_get_category_list(cl);
1390 if(list != NULL)
1393 gchar *name1 = gtodo_client_get_category_from_list(list);
1394 gint id = gtodo_client_get_category_id_from_list(list);
1395 if(strcmp(name1,name) == 0 && orig_id == 0)orig_id = id;
1396 }while(gtodo_client_get_list_next(list));
1398 if(orig_id == (cl->number_of_categories -1))
1400 gtodo_client_free_category_list(cl,list);
1401 return FALSE;
1403 gtodo_client_get_list_first(list);
1404 if(list != NULL)
1407 gchar *name1 = gtodo_client_get_category_from_list(list);
1408 gint id = gtodo_client_get_category_id_from_list(list);
1409 if(id == (orig_id +1) && under_name == NULL) under_name = g_strdup(name1);
1410 }while(gtodo_client_get_list_next(list));
1411 gtodo_client_free_category_list(cl,list);
1413 if(under_name == NULL) return FALSE;
1414 gtodo_client_category_set_id(cl, name, (orig_id +1));
1415 gtodo_client_category_set_id(cl, under_name, (orig_id));
1416 g_free(under_name);
1417 return TRUE;
1419 return FALSE;
1422 gboolean gtodo_client_category_exists(GTodoClient *cl, gchar *name)
1424 GTodoList *list = gtodo_client_get_category_list(cl);
1425 if(cl == NULL || name == NULL) return FALSE;
1426 if(list != NULL)
1429 if(!strcmp(name, gtodo_client_get_category_from_list(list)))
1431 gtodo_client_free_category_list(cl, list);
1432 return TRUE;
1434 }while(gtodo_client_get_list_next(list));
1436 return FALSE;
1439 gboolean gtodo_client_category_new(GTodoClient *cl, gchar *name)
1441 xmlNodePtr newn;
1442 gchar *buf = NULL;
1443 if(cl == NULL || name == NULL) return FALSE;
1444 if(gtodo_client_category_exists(cl, name)) return FALSE;
1445 newn = xmlNewTextChild(cl->root, NULL, (xmlChar *)"category", NULL);
1446 xmlNewProp(newn, (xmlChar *)"title", (xmlChar *)name);
1447 buf = g_strdup_printf("%i", cl->number_of_categories);
1448 cl->number_of_categories++;
1449 xmlNewProp(newn, (xmlChar *)"place", (xmlChar *)buf);
1450 g_free(buf);
1451 gtodo_client_save_xml(cl,NULL);
1452 return TRUE;
1455 gboolean gtodo_client_category_remove(GTodoClient *cl, gchar *name)
1457 gint id=-1;
1458 if(cl == NULL || name == NULL) return FALSE;
1459 if(!gtodo_client_category_exists(cl, name)) return FALSE;
1460 else
1462 xmlNodePtr cur = cl->root->xmlChildrenNode;
1463 /* gtodo_client_block_changed_callback(cl);
1464 */ while(cur != NULL){
1465 if(xmlStrEqual(cur->name, (xmlChar *)"category")){
1466 xmlChar *temp = xmlGetProp(cur, (const xmlChar *)"title");
1467 if(xmlStrEqual(temp, (const xmlChar *)name))
1469 xmlChar *idchar = xmlGetProp(cur, (const xmlChar *)"place");
1470 if(idchar != NULL) id = atoi((gchar *)idchar);
1471 xmlFree(idchar);
1472 xmlUnlinkNode(cur);
1473 xmlFreeNode(cur);
1474 cur = NULL;
1476 else cur = cur->next;
1477 xmlFree(temp);
1479 else cur = cur->next;
1482 gtodo_client_save_xml(cl,NULL);
1483 /* one number is removed.. now we need to renumber.. */
1484 if(id >= -1)
1486 GTodoList *list = gtodo_client_get_category_list(cl);
1487 if(list != NULL)
1490 int ref_id = gtodo_client_get_category_id_from_list(list);
1491 if(id < ref_id)
1493 gchar *name = gtodo_client_get_category_from_list(list);
1494 gtodo_client_category_set_id(cl, name, (ref_id -1));
1496 }while(gtodo_client_get_list_next(list));
1499 gtodo_client_free_category_list(cl, list);
1502 gtodo_client_save_xml(cl,NULL);
1503 /* this doesnt work.. have to adapt gtodo to do that
1504 gtodo_client_unblock_changed_callback(cl);
1506 return TRUE;
1510 void gtodo_client_block_changed_callback(GTodoClient *cl)
1512 if(cl->timeout != NULL)
1514 gnome_vfs_monitor_cancel(cl->timeout);
1516 cl->timeout = NULL;
1519 void gtodo_client_unblock_changed_callback(GTodoClient *cl)
1521 if(cl->timeout == NULL)
1523 gnome_vfs_monitor_add(&cl->timeout,cl->xml_path,
1524 GNOME_VFS_MONITOR_FILE,
1525 (GnomeVFSMonitorCallback)check_item_changed, cl);
1529 /* This function is deprecated now */
1530 void gtodo_client_reset_changed_callback(GTodoClient *cl)
1532 if(cl->timeout != NULL) return;
1535 void gtodo_client_get_list_first(GTodoList *list)
1537 list->list = list->first;
1540 /* als base niewer is dan test dan positief */
1541 long int gtodo_item_compare_latest(GTodoItem *base, GTodoItem *test)
1543 if(base == NULL || test == NULL) return 0;
1544 return base->last_edited-test->last_edited;
1547 /* make duplicate an exact copy of source */
1548 void gtodo_client_save_client_to_client(GTodoClient *source, GTodoClient *duplicate)
1550 gtodo_client_save_xml_to_file(source, duplicate->xml_path,NULL);
1551 gtodo_client_reload(duplicate);
1554 gboolean gtodo_client_get_read_only(GTodoClient *cl)
1556 if(cl == NULL) return FALSE;
1557 return cl->read_only;