1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * GThumb
5 *
6 * Copyright (C) 2009 The Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <string.h>
24 #include <gthumb.h>
25 #include "gth-comment.h"
26
27
28 #define COMMENT_VERSION "3.0"
29
30
31 struct _GthCommentPrivate { /* All strings in utf8 format. */
32 char *caption;
33 char *note;
34 char *place;
35 int rating;
36 GPtrArray *categories;
37 GDate *date;
38 GthTime *time_of_day;
39 gboolean changed;
40 gboolean utf8;
41 };
42
43
44 static void gth_comment_gth_duplicable_interface_init (GthDuplicableInterface *iface);
45 static void gth_comment_dom_domizable_interface_init (DomDomizableInterface *iface);
46
47
G_DEFINE_TYPE_WITH_CODE(GthComment,gth_comment,G_TYPE_OBJECT,G_ADD_PRIVATE (GthComment)G_IMPLEMENT_INTERFACE (GTH_TYPE_DUPLICABLE,gth_comment_gth_duplicable_interface_init)G_IMPLEMENT_INTERFACE (DOM_TYPE_DOMIZABLE,gth_comment_dom_domizable_interface_init))48 G_DEFINE_TYPE_WITH_CODE (GthComment,
49 gth_comment,
50 G_TYPE_OBJECT,
51 G_ADD_PRIVATE (GthComment)
52 G_IMPLEMENT_INTERFACE (GTH_TYPE_DUPLICABLE,
53 gth_comment_gth_duplicable_interface_init)
54 G_IMPLEMENT_INTERFACE (DOM_TYPE_DOMIZABLE,
55 gth_comment_dom_domizable_interface_init))
56
57
58 static void
59 gth_comment_free_data (GthComment *self)
60 {
61 if (self->priv->place != NULL) {
62 g_free (self->priv->place);
63 self->priv->place = NULL;
64 }
65
66 if (self->priv->note != NULL) {
67 g_free (self->priv->note);
68 self->priv->note = NULL;
69 }
70
71 if (self->priv->caption != NULL) {
72 g_free (self->priv->caption);
73 self->priv->caption = NULL;
74 }
75 }
76
77
78 static void
gth_comment_finalize(GObject * obj)79 gth_comment_finalize (GObject *obj)
80 {
81 GthComment *self = GTH_COMMENT (obj);
82
83 gth_comment_free_data (self);
84 gth_comment_clear_categories (self);
85 g_ptr_array_unref (self->priv->categories);
86 g_date_free (self->priv->date);
87 gth_time_free (self->priv->time_of_day);
88
89 G_OBJECT_CLASS (gth_comment_parent_class)->finalize (obj);
90 }
91
92
93 static void
gth_comment_class_init(GthCommentClass * klass)94 gth_comment_class_init (GthCommentClass *klass)
95 {
96 G_OBJECT_CLASS (klass)->finalize = gth_comment_finalize;
97 }
98
99
100 static void
gth_comment_init(GthComment * self)101 gth_comment_init (GthComment *self)
102 {
103 self->priv = gth_comment_get_instance_private (self);
104 self->priv->caption = NULL;
105 self->priv->note = NULL;
106 self->priv->place = NULL;
107 self->priv->rating = 0;
108 self->priv->categories = g_ptr_array_new ();
109 self->priv->date = g_date_new ();
110 self->priv->time_of_day = gth_time_new ();
111 }
112
113
114 static GObject *
gth_comment_real_duplicate(GthDuplicable * base)115 gth_comment_real_duplicate (GthDuplicable *base)
116 {
117 return (GObject *) gth_comment_dup ((GthComment*) base);
118 }
119
120
121 static void
gth_comment_gth_duplicable_interface_init(GthDuplicableInterface * iface)122 gth_comment_gth_duplicable_interface_init (GthDuplicableInterface *iface)
123 {
124 iface->duplicate = gth_comment_real_duplicate;
125 }
126
127
128 static DomElement*
gth_comment_real_create_element(DomDomizable * base,DomDocument * doc)129 gth_comment_real_create_element (DomDomizable *base,
130 DomDocument *doc)
131 {
132 GthComment *self;
133 DomElement *element;
134 char *value;
135 GPtrArray *categories;
136 DomElement *categories_element;
137 int i;
138
139 g_return_val_if_fail (DOM_IS_DOCUMENT (doc), NULL);
140
141 self = GTH_COMMENT (base);
142 element = dom_document_create_element (doc, "comment",
143 "version", COMMENT_VERSION,
144 NULL);
145
146 dom_element_append_child (element, dom_document_create_element_with_text (doc, self->priv->caption, "caption", NULL));
147 dom_element_append_child (element, dom_document_create_element_with_text (doc, self->priv->note, "note", NULL));
148 dom_element_append_child (element, dom_document_create_element_with_text (doc, self->priv->place, "place", NULL));
149
150 if (self->priv->rating > 0) {
151 value = g_strdup_printf ("%d", self->priv->rating);
152 dom_element_append_child (element, dom_document_create_element (doc, "rating", "value", value, NULL));
153 g_free (value);
154 }
155
156 value = gth_comment_get_time_as_exif_format (self);
157 if (value != NULL) {
158 dom_element_append_child (element, dom_document_create_element (doc, "time", "value", value, NULL));
159 g_free (value);
160 }
161
162 categories = gth_comment_get_categories (self);
163 categories_element = dom_document_create_element (doc, "categories", NULL);
164 dom_element_append_child (element, categories_element);
165 for (i = 0; i < categories->len; i++)
166 dom_element_append_child (categories_element, dom_document_create_element (doc, "category", "value", g_ptr_array_index (categories, i), NULL));
167
168 return element;
169 }
170
171
172 static void
gth_comment_real_load_from_element(DomDomizable * base,DomElement * element)173 gth_comment_real_load_from_element (DomDomizable *base,
174 DomElement *element)
175 {
176 GthComment *self;
177 DomElement *node;
178
179 g_return_if_fail (DOM_IS_ELEMENT (element));
180
181 self = GTH_COMMENT (base);
182 gth_comment_reset (self);
183
184 if (g_strcmp0 (dom_element_get_attribute (element, "format"), "2.0") == 0) {
185 for (node = element->first_child; node; node = node->next_sibling) {
186 if (g_strcmp0 (node->tag_name, "Note") == 0)
187 gth_comment_set_note (self, dom_element_get_inner_text (node));
188 else if (g_strcmp0 (node->tag_name, "Place") == 0)
189 gth_comment_set_place (self, dom_element_get_inner_text (node));
190 else if (g_strcmp0 (node->tag_name, "Time") == 0)
191 gth_comment_set_time_from_time_t (self, atol (dom_element_get_inner_text (node)));
192 else if (g_strcmp0 (node->tag_name, "Keywords") == 0) {
193 const char *text;
194
195 text = dom_element_get_inner_text (node);
196 if (text != NULL) {
197 char **categories;
198 int i;
199
200 categories = g_strsplit (text, ",", -1);
201 for (i = 0; categories[i] != NULL; i++)
202 gth_comment_add_category (self, categories[i]);
203 g_strfreev (categories);
204 }
205 }
206 }
207 }
208 else if (g_strcmp0 (dom_element_get_attribute (element, "version"), "3.0") == 0) {
209 for (node = element->first_child; node; node = node->next_sibling) {
210 if (g_strcmp0 (node->tag_name, "caption") == 0)
211 gth_comment_set_caption (self, dom_element_get_inner_text (node));
212 else if (g_strcmp0 (node->tag_name, "note") == 0)
213 gth_comment_set_note (self, dom_element_get_inner_text (node));
214 else if (g_strcmp0 (node->tag_name, "place") == 0)
215 gth_comment_set_place (self, dom_element_get_inner_text (node));
216 else if (g_strcmp0 (node->tag_name, "time") == 0)
217 gth_comment_set_time_from_exif_format (self, dom_element_get_attribute (node, "value"));
218 else if (g_strcmp0 (node->tag_name, "rating") == 0) {
219 int v;
220
221 sscanf (dom_element_get_attribute (node, "value"), "%d", &v);
222 gth_comment_set_rating (self, v);
223 }
224 else if (g_strcmp0 (node->tag_name, "categories") == 0) {
225 DomElement *child;
226
227 for (child = node->first_child; child != NULL; child = child->next_sibling)
228 if (strcmp (child->tag_name, "category") == 0)
229 gth_comment_add_category (self, dom_element_get_attribute (child, "value"));
230 }
231 }
232 }
233 }
234
235
236 static void
gth_comment_dom_domizable_interface_init(DomDomizableInterface * iface)237 gth_comment_dom_domizable_interface_init (DomDomizableInterface *iface)
238 {
239 iface->create_element = gth_comment_real_create_element;
240 iface->load_from_element = gth_comment_real_load_from_element;
241 }
242
243
244 GthComment *
gth_comment_new(void)245 gth_comment_new (void)
246 {
247 return g_object_new (GTH_TYPE_COMMENT, NULL);
248 }
249
250
251 GFile *
gth_comment_get_comment_file(GFile * file)252 gth_comment_get_comment_file (GFile *file)
253 {
254 GFile *parent;
255 char *basename;
256 char *comment_basename;
257 GFile *comment_file;
258
259 parent = g_file_get_parent (file);
260 if (parent == NULL)
261 return NULL;
262
263 basename = g_file_get_basename (file);
264 comment_basename = g_strconcat (basename, ".xml", NULL);
265 comment_file = _g_file_get_child (parent, ".comments", comment_basename, NULL);
266
267 g_free (comment_basename);
268 g_free (basename);
269 g_object_unref (parent);
270
271 return comment_file;
272 }
273
274
275 GthComment *
gth_comment_new_for_file(GFile * file,GCancellable * cancellable,GError ** error)276 gth_comment_new_for_file (GFile *file,
277 GCancellable *cancellable,
278 GError **error)
279 {
280 GFile *comment_file;
281 GthComment *comment;
282 void *zipped_buffer;
283 gsize zipped_size;
284 void *buffer;
285 gsize size;
286 DomDocument *doc;
287
288 comment_file = gth_comment_get_comment_file (file);
289 if (comment_file == NULL)
290 return NULL;
291
292 if (! _g_file_load_in_buffer (comment_file, &zipped_buffer, &zipped_size, cancellable, error)) {
293 g_object_unref (comment_file);
294 return NULL;
295 }
296 g_object_unref (comment_file);
297
298 if ((zipped_buffer != NULL) && (((char *) zipped_buffer)[0] != '<')) {
299 if (! zlib_decompress_buffer (zipped_buffer, zipped_size, &buffer, &size))
300 return NULL;
301 }
302 else {
303 buffer = zipped_buffer;
304 size = zipped_size;
305
306 zipped_buffer = NULL;
307 }
308
309 comment = gth_comment_new ();
310 doc = dom_document_new ();
311 if (dom_document_load (doc, buffer, size, error)) {
312 dom_domizable_load_from_element (DOM_DOMIZABLE (comment), DOM_ELEMENT (doc)->first_child);
313 }
314 else {
315 buffer = NULL;
316 g_object_unref (comment);
317 comment = NULL;
318 }
319
320 g_object_unref (doc);
321 g_free (buffer);
322 g_free (zipped_buffer);
323
324 return comment;
325 }
326
327
328 char *
gth_comment_to_data(GthComment * comment,gsize * length)329 gth_comment_to_data (GthComment *comment,
330 gsize *length)
331 {
332 DomDocument *doc;
333 char *data;
334
335 doc = dom_document_new ();
336 dom_element_append_child (DOM_ELEMENT (doc), dom_domizable_create_element (DOM_DOMIZABLE (comment), doc));
337 data = dom_document_dump (doc, length);
338
339 g_object_unref (doc);
340
341 return data;
342 }
343
344
345 GthComment *
gth_comment_dup(GthComment * self)346 gth_comment_dup (GthComment *self)
347 {
348 GthComment *comment;
349 char *time;
350 int i;
351
352 if (self == NULL)
353 return NULL;
354
355 comment = gth_comment_new ();
356 gth_comment_set_caption (comment, gth_comment_get_caption (self));
357 gth_comment_set_note (comment, gth_comment_get_note (self));
358 gth_comment_set_place (comment, gth_comment_get_place (self));
359 gth_comment_set_rating (comment, gth_comment_get_rating (self));
360 time = gth_comment_get_time_as_exif_format (self);
361 gth_comment_set_time_from_exif_format (comment, time);
362 for (i = 0; i < self->priv->categories->len; i++)
363 gth_comment_add_category (comment, g_ptr_array_index (self->priv->categories, i));
364
365 g_free (time);
366
367 return comment;
368 }
369
370
371 void
gth_comment_reset(GthComment * self)372 gth_comment_reset (GthComment *self)
373 {
374 gth_comment_free_data (self);
375 gth_comment_clear_categories (self);
376 gth_comment_reset_time (self);
377 }
378
379
380 void
gth_comment_set_caption(GthComment * comment,const char * value)381 gth_comment_set_caption (GthComment *comment,
382 const char *value)
383 {
384 g_free (comment->priv->caption);
385 comment->priv->caption = NULL;
386
387 if ((value != NULL) && (strcmp (value, "") != 0))
388 comment->priv->caption = g_strdup (value);
389 }
390
391
392 void
gth_comment_set_note(GthComment * comment,const char * value)393 gth_comment_set_note (GthComment *comment,
394 const char *value)
395 {
396 g_free (comment->priv->note);
397 comment->priv->note = NULL;
398
399 if ((value != NULL) && (strcmp (value, "") != 0))
400 comment->priv->note = g_strdup (value);
401 }
402
403
404 void
gth_comment_set_place(GthComment * comment,const char * value)405 gth_comment_set_place (GthComment *comment,
406 const char *value)
407 {
408 g_free (comment->priv->place);
409 comment->priv->place = NULL;
410
411 if ((value != NULL) && (strcmp (value, "") != 0))
412 comment->priv->place = g_strdup (value);
413 }
414
415
416 void
gth_comment_set_rating(GthComment * comment,int value)417 gth_comment_set_rating (GthComment *comment,
418 int value)
419 {
420 comment->priv->rating = value;
421 }
422
423
424 void
gth_comment_clear_categories(GthComment * self)425 gth_comment_clear_categories (GthComment *self)
426 {
427 g_ptr_array_foreach (self->priv->categories, (GFunc) g_free, NULL);
428 g_ptr_array_unref (self->priv->categories);
429 self->priv->categories = g_ptr_array_new ();
430 }
431
432
433 void
gth_comment_add_category(GthComment * comment,const char * value)434 gth_comment_add_category (GthComment *comment,
435 const char *value)
436 {
437 g_return_if_fail (value != NULL);
438
439 g_ptr_array_add (comment->priv->categories, g_strdup (value));
440 }
441
442
443 void
gth_comment_reset_time(GthComment * self)444 gth_comment_reset_time (GthComment *self)
445 {
446 g_date_clear (self->priv->date, 1);
447 gth_time_clear (self->priv->time_of_day);
448 }
449
450
451 void
gth_comment_set_time_from_exif_format(GthComment * comment,const char * value)452 gth_comment_set_time_from_exif_format (GthComment *comment,
453 const char *value)
454 {
455 unsigned int y, m, d, hh, mm, ss;
456
457 gth_comment_reset_time (comment);
458
459 if ((value == NULL) || (*value == '\0'))
460 return;
461
462 if (sscanf (value, "%u:%u:%u %u:%u:%u", &y, &m, &d, &hh, &mm, &ss) != 6) {
463 g_warning ("invalid time format: %s", value);
464 return;
465 }
466
467 if (g_date_valid_dmy (d, m, y)) {
468 g_date_set_dmy (comment->priv->date, d, m, y);
469 gth_time_set_hms (comment->priv->time_of_day, hh, mm, ss, 0);
470 }
471 }
472
473
474 void
gth_comment_set_time_from_time_t(GthComment * comment,time_t value)475 gth_comment_set_time_from_time_t (GthComment *comment,
476 time_t value)
477 {
478 struct tm *tm;
479
480 if (value == 0)
481 return;
482
483 tm = localtime (&value);
484 g_date_set_dmy (comment->priv->date, tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
485 gth_time_set_hms (comment->priv->time_of_day, tm->tm_hour, tm->tm_min, tm->tm_sec, 0);
486 }
487
488
489 const char *
gth_comment_get_caption(GthComment * comment)490 gth_comment_get_caption (GthComment *comment)
491 {
492 return comment->priv->caption;
493 }
494
495
496 const char *
gth_comment_get_note(GthComment * comment)497 gth_comment_get_note (GthComment *comment)
498 {
499 return comment->priv->note;
500 }
501
502
503 const char *
gth_comment_get_place(GthComment * comment)504 gth_comment_get_place (GthComment *comment)
505 {
506 return comment->priv->place;
507 }
508
509
510 int
gth_comment_get_rating(GthComment * comment)511 gth_comment_get_rating (GthComment *comment)
512 {
513 return comment->priv->rating;
514 }
515
516
517 GPtrArray *
gth_comment_get_categories(GthComment * comment)518 gth_comment_get_categories (GthComment *comment)
519 {
520 return comment->priv->categories;
521 }
522
523
524 GDate *
gth_comment_get_date(GthComment * comment)525 gth_comment_get_date (GthComment *comment)
526 {
527 return comment->priv->date;
528 }
529
530
531 GthTime *
gth_comment_get_time_of_day(GthComment * comment)532 gth_comment_get_time_of_day (GthComment *comment)
533 {
534 return comment->priv->time_of_day;
535 }
536
537
538 char *
gth_comment_get_time_as_exif_format(GthComment * comment)539 gth_comment_get_time_as_exif_format (GthComment *comment)
540 {
541 char *s;
542
543 if (! g_date_valid (comment->priv->date))
544 return NULL;
545
546 s = g_strdup_printf ("%04u:%02u:%02u %02u:%02u:%02u",
547 g_date_get_year (comment->priv->date),
548 g_date_get_month (comment->priv->date),
549 g_date_get_day (comment->priv->date),
550 comment->priv->time_of_day->hour,
551 comment->priv->time_of_day->min,
552 comment->priv->time_of_day->sec);
553
554 return s;
555 }
556
557
558 void
gth_comment_update_general_attributes(GthFileData * file_data)559 gth_comment_update_general_attributes (GthFileData *file_data)
560 {
561 const char *value;
562
563 value = g_file_info_get_attribute_string (file_data->info, "comment::note");
564 if (value != NULL)
565 set_attribute_from_string (file_data->info,
566 "general::description",
567 value,
568 NULL);
569
570 value = g_file_info_get_attribute_string (file_data->info, "comment::caption");
571 if (value != NULL)
572 set_attribute_from_string (file_data->info,
573 "general::title",
574 value,
575 NULL);
576
577 value = g_file_info_get_attribute_string (file_data->info, "comment::place");
578 if (value != NULL)
579 set_attribute_from_string (file_data->info,
580 "general::location",
581 value,
582 NULL);
583
584 if (g_file_info_has_attribute (file_data->info, "comment::rating")) {
585 char *v;
586
587 v = g_strdup_printf ("%d", g_file_info_get_attribute_int32 (file_data->info, "comment::rating"));
588 set_attribute_from_string (file_data->info, "general::rating", v, NULL);
589
590 g_free (v);
591 }
592
593 if (g_file_info_has_attribute (file_data->info, "comment::categories"))
594 g_file_info_set_attribute_object (file_data->info,
595 "general::tags",
596 g_file_info_get_attribute_object (file_data->info, "comment::categories"));
597
598 if (g_file_info_has_attribute (file_data->info, "comment::time"))
599 g_file_info_set_attribute_object (file_data->info,
600 "general::datetime",
601 g_file_info_get_attribute_object (file_data->info, "comment::time"));
602 }
603
604
605 void
gth_comment_update_from_general_attributes(GthFileData * file_data)606 gth_comment_update_from_general_attributes (GthFileData *file_data)
607 {
608 gboolean write_comment;
609 GthMetadata *metadata;
610 GthStringList *comment_categories;
611 GList *scan;
612 const char *text;
613 GthComment *comment;
614 GthStringList *categories;
615
616 write_comment = FALSE;
617
618 comment = gth_comment_new ();
619 gth_comment_set_note (comment, g_file_info_get_attribute_string (file_data->info, "comment::note"));
620 gth_comment_set_caption (comment, g_file_info_get_attribute_string (file_data->info, "comment::caption"));
621 gth_comment_set_place (comment, g_file_info_get_attribute_string (file_data->info, "comment::place"));
622
623 metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "comment::time");
624 if (metadata != NULL)
625 gth_comment_set_time_from_exif_format (comment, gth_metadata_get_raw (metadata));
626
627 metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "comment::categories");
628 comment_categories = gth_metadata_get_string_list (metadata);
629 if (comment_categories != NULL)
630 for (scan = gth_string_list_get_list (comment_categories); scan; scan = scan->next)
631 gth_comment_add_category (comment, (char *) scan->data);
632
633 gth_comment_set_rating (comment, g_file_info_get_attribute_int32 (file_data->info, "comment::rating"));
634
635 /* sync embedded data and .comment data if required */
636
637 metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "general::description");
638 if (metadata != NULL) {
639 text = g_file_info_get_attribute_string (file_data->info, "comment::note");
640 if (! dom_str_equal (gth_metadata_get_formatted (metadata), text)) {
641 char *value = _g_utf8_try_from_any (gth_metadata_get_formatted (metadata));
642 if (value != NULL) {
643 gth_comment_set_note (comment, value);
644 g_free (value);
645 write_comment = TRUE;
646 }
647 }
648 }
649
650 metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "general::title");
651 if (metadata != NULL) {
652 text = g_file_info_get_attribute_string (file_data->info, "comment::caption");
653 if (! dom_str_equal (gth_metadata_get_formatted (metadata), text)) {
654 char *value = _g_utf8_try_from_any (gth_metadata_get_formatted (metadata));
655 if (value != NULL) {
656 gth_comment_set_caption (comment, value);
657 g_free (value);
658 write_comment = TRUE;
659 }
660 }
661 }
662
663 metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "general::location");
664 if (metadata != NULL) {
665 text = g_file_info_get_attribute_string (file_data->info, "comment::place");
666 if (! dom_str_equal (gth_metadata_get_formatted (metadata), text)) {
667 char *value = _g_utf8_try_from_any (gth_metadata_get_formatted (metadata));
668 if (value != NULL) {
669 gth_comment_set_place (comment, value);
670 g_free (value);
671 write_comment = TRUE;
672 }
673 }
674 }
675
676 metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "general::datetime");
677 if (metadata != NULL) {
678 GthMetadata *comment_time;
679
680 text = gth_metadata_get_raw (metadata);
681 comment_time = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "comment::time");
682 if (comment_time != NULL) {
683 if (! dom_str_equal (gth_metadata_get_raw (comment_time), text)) {
684 gth_comment_set_time_from_exif_format (comment, gth_metadata_get_raw (metadata));
685 write_comment = TRUE;
686 }
687 }
688 }
689
690 metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "general::tags");
691 categories = gth_metadata_get_string_list (metadata);
692 if (categories != NULL) {
693 metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "comment::categories");
694 comment_categories = gth_metadata_get_string_list (metadata);
695 if (! gth_string_list_equal_custom (categories, comment_categories, (GCompareFunc) dom_str_find)) {
696 GList *scan;
697
698 gth_comment_clear_categories (comment);
699 for (scan = gth_string_list_get_list (categories); scan; scan = scan->next) {
700 char *value = _g_utf8_try_from_any (scan->data);
701 if (value != NULL) {
702 gth_comment_add_category (comment, value);
703 g_free (value);
704 }
705 }
706 write_comment = TRUE;
707 }
708 }
709
710 if (write_comment) {
711 GFile *comment_file;
712 GFile *comment_directory;
713 char *buffer;
714 gsize size;
715
716 comment_file = gth_comment_get_comment_file (file_data->file);
717 comment_directory = g_file_get_parent (comment_file);
718 if (! g_file_query_exists (comment_directory, NULL))
719 g_file_make_directory (comment_directory, NULL, NULL);
720
721 buffer = gth_comment_to_data (comment, &size);
722 if (_g_file_write (comment_file,
723 FALSE,
724 G_FILE_CREATE_NONE,
725 buffer,
726 size,
727 NULL,
728 NULL))
729 {
730 GFile *parent;
731 GList *list;
732
733 parent = g_file_get_parent (file_data->file);
734 list = g_list_prepend (NULL, file_data->file);
735 gth_monitor_folder_changed (gth_main_get_default_monitor (),
736 parent,
737 list,
738 GTH_MONITOR_EVENT_CHANGED);
739
740 g_list_free (list);
741 g_object_unref (parent);
742 }
743
744 g_free (buffer);
745 g_object_unref (comment_directory);
746 g_object_unref (comment_file);
747 }
748
749 g_object_unref (comment);
750 }
751