changeset 1238:947e603a52c6

simplified metadata interface, dropped metadata_read, fixes for older exiv2 versions
author nadvornik
date Sat, 10 Jan 2009 20:40:37 +0000
parents 824a1e1775b8
children 254b09942e68
files src/bar_info.c src/exif.c src/exif.h src/exiv2.cc src/image-overlay.c src/metadata.c src/metadata.h src/search.c src/ui_fileops.c src/ui_fileops.h src/view_file_icon.c src/view_file_list.c
diffstat 12 files changed, 291 insertions(+), 218 deletions(-) [+]
line wrap: on
line diff
--- a/src/bar_info.c	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/bar_info.c	Sat Jan 10 20:40:37 2009 +0000
@@ -509,25 +509,16 @@
 		gtk_label_set_text(GTK_LABEL(bd->label_file_time), (bd->fd) ? text_from_time(bd->fd->date) : "");
 		}
 
-	if (metadata_read(bd->fd, &keywords, &comment))
-		{
-		keyword_list_push(bd->keyword_view, keywords);
-		gtk_text_buffer_set_text(comment_buffer,
-					 (comment) ? comment : "", -1);
-
-		bar_keyword_list_sync(bd, keywords);
-
-		string_list_free(keywords);
-		g_free(comment);
-		}
-	else
-		{
-		gtk_text_buffer_set_text(keyword_buffer, "", -1);
-		gtk_text_buffer_set_text(comment_buffer, "", -1);
-
-		bar_keyword_list_sync(bd, NULL);
-		}
-
+	comment = metadata_read_string(bd->fd, COMMENT_KEY);
+	gtk_text_buffer_set_text(comment_buffer,
+				 (comment) ? comment : "", -1);
+	g_free(comment);
+	
+	keywords = metadata_read_list(bd->fd, KEYWORD_KEY);
+	keyword_list_push(bd->keyword_view, keywords);
+	bar_keyword_list_sync(bd, keywords);
+	string_list_free(keywords);
+	
 	g_signal_handlers_unblock_by_func(keyword_buffer, bar_info_changed, bd);
 	g_signal_handlers_unblock_by_func(comment_buffer, bar_info_changed, bd);
 
@@ -667,7 +658,16 @@
 		FileData *fd = work->data;
 		work = work->next;
 
-		metadata_set(fd, keywords, comment, append);
+		if (append)
+			{
+			if (comment) metadata_append_string(fd, COMMENT_KEY, comment);
+			if (keywords) metadata_append_list(fd, KEYWORD_KEY, keywords);
+			}
+		else
+			{
+			if (comment) metadata_write_string(fd, COMMENT_KEY, comment);
+			if (keywords) metadata_write_list(fd, KEYWORD_KEY, keywords);
+			}
 		}
 
 	filelist_free(list);
--- a/src/exif.c	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/exif.c	Sat Jan 10 20:40:37 2009 +0000
@@ -1367,7 +1367,7 @@
 				}
 			break;
 		case EXIF_FORMAT_STRING:
-			string = g_string_append(string, (gchar *)(item->data));
+			if (item->data) string = g_string_append(string, (gchar *)(item->data));
 			break;
 		case EXIF_FORMAT_SHORT_UNSIGNED:
 			if (ne == 1 && marker->list)
@@ -1596,6 +1596,19 @@
 	return 0;
 }
 
+GList *exif_get_metadata(ExifData *exif, const gchar *key)
+{
+	gchar *str;
+	ExifItem *item = exif_get_item(exif, key);
+	if (!item) return NULL;
+	
+	str = exif_item_get_string(item, 0);
+	
+	if (!str) return NULL;
+	
+	return g_list_append(NULL, str);
+}
+
 typedef struct _UnmapData UnmapData;
 struct _UnmapData
 {
--- a/src/exif.h	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/exif.h	Sat Jan 10 20:40:37 2009 +0000
@@ -151,6 +151,7 @@
 gchar *exif_get_formatted_by_key(ExifData *exif, const gchar *key, gint *key_valid);
 
 gint exif_update_metadata(ExifData *exif, const gchar *key, const GList *values);
+GList *exif_get_metadata(ExifData *exif, const gchar *key);
 
 guchar *exif_get_color_profile(ExifData *exif, guint *data_len);
 
--- a/src/exiv2.cc	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/exiv2.cc	Sat Jan 10 20:40:37 2009 +0000
@@ -53,7 +53,6 @@
 #include <exiv2/xmpsidecar.hpp>
 #endif
 
-
 extern "C" {
 #include <glib.h>
 
@@ -62,8 +61,28 @@
 
 #include "filefilter.h"
 #include "ui_fileops.h"
+
+#include "misc.h"
 }
 
+typedef struct _AltKey AltKey;
+
+struct _AltKey
+{
+	const gchar *xmp_key;
+	const gchar *exif_key;
+	const gchar *iptc_key;
+};
+
+/* this is a list of keys that should be converted, even with the older Exiv2 which does not support it directly */
+static const AltKey alt_keys[] = {
+	{"Xmp.tiff.Orientation", "Exif.Image.Orientation", NULL},
+	{"Xmp.dc.subject", NULL, "Iptc.Application2.Keywords"},
+	{"Xmp.dc.description", NULL, "Iptc.Application2.Caption"},
+	{NULL, NULL, NULL}
+	};
+
+
 struct _ExifData
 {
 	Exiv2::ExifData::const_iterator exifIter; /* for exif_get_next_item */
@@ -259,13 +278,15 @@
 
 	virtual void writeMetadata(gchar *path = NULL)
 	{
-#if EXIV2_TEST_VERSION(0,17,0)
-		syncExifWithXmp(exifData_, xmpData_);
-#endif
 		if (!path)
 			{
 #if EXIV2_TEST_VERSION(0,17,0)
-			if (options->metadata.save_legacy_IPTC) copyXmpToIptc(xmpData_, iptcData_);
+			if (options->metadata.save_legacy_IPTC) 
+				copyXmpToIptc(xmpData_, iptcData_);
+			else
+				iptcData_.clear();
+
+			copyXmpToExif(xmpData_, exifData_);
 #endif
 			imageData_->image()->setExifData(exifData_);
 			imageData_->image()->setIptcData(iptcData_);
@@ -749,7 +770,19 @@
 	}
 }
 
-gint exif_update_metadata(ExifData *exif, const gchar *key, const GList *values)
+static const AltKey *find_alt_key(const gchar *xmp_key)
+{
+	gint i = 0;
+	
+	while (alt_keys[i].xmp_key)
+		{
+		if (strcmp(xmp_key, alt_keys[i].xmp_key) == 0) return &alt_keys[i];
+		i++;
+		}
+	return NULL;
+}
+
+static gint exif_update_metadata_simple(ExifData *exif, const gchar *key, const GList *values)
 {
 	try {
 		const GList *work = values;
@@ -801,6 +834,8 @@
 					exif->xmpData()[key] = (gchar *)work->data;
 					work = work->next;
 					}
+#else
+				throw e;
 #endif
 			}
 		}
@@ -812,6 +847,127 @@
 	}
 }
 
+gint exif_update_metadata(ExifData *exif, const gchar *key, const GList *values)
+{
+	gint ret = exif_update_metadata_simple(exif, key, values);
+	
+	if (
+#if !EXIV2_TEST_VERSION(0,17,0)
+	    TRUE || /* no conversion support */
+#endif
+	    !values || /* deleting item */
+	    !ret  /* writing to the explicitely given xmp tag failed */
+	    )
+		{
+		/* deleted xmp metadatum can't be converted, we have to delete also the corresponding legacy tag */
+		/* if we can't write xmp, update at least the legacy tag */
+		const AltKey *alt_key = find_alt_key(key);
+		if (alt_key && alt_key->iptc_key)
+			ret = exif_update_metadata_simple(exif, alt_key->iptc_key, values);
+
+		if (alt_key && alt_key->exif_key)
+			ret = exif_update_metadata_simple(exif, alt_key->exif_key, values);
+		}
+	return ret;
+}
+
+
+static GList *exif_add_value_to_glist(GList *list, Exiv2::Metadatum &item)
+{
+	Exiv2::TypeId id = item.typeId();
+	if (id == Exiv2::asciiString ||
+	    id == Exiv2::undefined ||
+	    id == Exiv2::string ||
+	    id == Exiv2::date ||
+	    id == Exiv2::time ||
+#if EXIV2_TEST_VERSION(0,16,0)
+	    id == Exiv2::xmpText ||
+	    id == Exiv2::langAlt ||
+#endif 
+	    id == Exiv2::comment
+	    )
+		{
+		/* read as a single entry */
+		std::string str = item.toString();
+		if (str.length() > 5 && str.substr(0, 5) == "lang=")
+			{
+			std::string::size_type pos = str.find_first_of(' ');
+			if (pos != std::string::npos) str = str.substr(pos+1);
+			}
+		list = g_list_append(list, utf8_validate_or_convert(str.c_str())); 
+		}
+	else
+		{
+		/* read as a list */
+		gint i;
+		for (i = 0; i < item.count(); i++)
+			list = g_list_append(list, utf8_validate_or_convert(item.toString(i).c_str())); 
+		}
+	return list;
+}
+
+static GList *exif_get_metadata_simple(ExifData *exif, const gchar *key)
+{
+	GList *list = NULL;
+	try {
+		try {
+			Exiv2::ExifKey ekey(key);
+			
+			Exiv2::ExifData::iterator pos = exif->exifData().findKey(ekey);
+			if (pos != exif->exifData().end())
+				list = exif_add_value_to_glist(list, *pos);
+
+		}
+		catch (Exiv2::AnyError& e) {
+			try {
+				Exiv2::IptcKey ekey(key);
+				Exiv2::IptcData::iterator pos = exif->iptcData().begin();
+				while (pos != exif->iptcData().end())
+					{
+					if (pos->key() == key)
+						list = exif_add_value_to_glist(list, *pos);
+					++pos;
+					}
+
+			}
+			catch (Exiv2::AnyError& e) {
+#if EXIV2_TEST_VERSION(0,16,0)
+				Exiv2::XmpKey ekey(key);
+				Exiv2::XmpData::iterator pos = exif->xmpData().findKey(ekey);
+				if (pos != exif->xmpData().end())
+					list = exif_add_value_to_glist(list, *pos);
+#endif
+			}
+		}
+	}
+	catch (Exiv2::AnyError& e) {
+		std::cout << "Caught Exiv2 exception '" << e << "'\n";
+	}
+	return list;
+}
+
+GList *exif_get_metadata(ExifData *exif, const gchar *key)
+{
+	GList *list = NULL;
+	
+	list = exif_get_metadata_simple(exif, key);
+	
+	/* the following code can be ifdefed out as soon as Exiv2 supports it */
+	if (!list)
+		{
+		const AltKey *alt_key = find_alt_key(key);
+		if (alt_key && alt_key->iptc_key)
+			list = exif_get_metadata_simple(exif, alt_key->iptc_key);
+
+#if !EXIV2_TEST_VERSION(0,17,0)	
+		/* with older Exiv2 versions exif is not synced */
+		if (!list && alt_key && alt_key->exif_key)
+			list = exif_get_metadata_simple(exif, alt_key->exif_key);
+#endif
+		}
+	return list;
+}
+
 
 void exif_add_jpeg_color_profile(ExifData *exif, unsigned char *cp_data, guint cp_length)
 {
--- a/src/image-overlay.c	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/image-overlay.c	Sat Jan 10 20:40:37 2009 +0000
@@ -178,7 +178,9 @@
 
 	g_assert(fd);
 
-	if (metadata_read(fd, &keywords, NULL))
+	keywords = metadata_read_list(fd, KEYWORD_KEY);
+
+	if (keywords)
 		{
 		GList *work = keywords;
 
@@ -195,6 +197,7 @@
 			
 			g_string_append(kwstr, kw);
 			}
+		string_list_free(keywords);
 		}
 
 	if (kwstr)
@@ -275,7 +278,7 @@
 			}
 		else if (strcmp(name, "comment") == 0)
 			{
-			metadata_read(imd->image_fd, NULL, &data);
+			data = metadata_read_string(imd->image_fd, COMMENT_KEY);
 			}
 		else
 			{
--- a/src/metadata.c	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/metadata.c	Sat Jan 10 20:40:37 2009 +0000
@@ -325,7 +325,15 @@
 	
 	fclose(f);
 
-	*keywords = g_list_reverse(list);
+	if (keywords) 
+		{
+		*keywords = g_list_reverse(list);
+		}
+	else
+		{
+		string_list_free(list);
+		}
+		
 	if (comment_build)
 		{
 		if (comment)
@@ -420,209 +428,93 @@
 	return g_list_reverse(newlist);
 }
 
-
-static gint metadata_xmp_read(FileData *fd, GList **keywords, gchar **comment)
+GList *metadata_read_list(FileData *fd, const gchar *key)
 {
 	ExifData *exif;
+	GList *list = NULL;
+	if (!fd) return NULL;
 
-	exif = exif_read_fd(fd);
-	if (!exif) return FALSE;
-
-	if (comment)
+	/* unwritten data overide everything */
+	if (fd->modified_xmp)
 		{
-		gchar *text;
-		ExifItem *item = exif_get_item(exif, COMMENT_KEY);
-
-		text = exif_item_get_string(item, 0);
-		*comment = utf8_validate_or_convert(text);
-		g_free(text);
+	        list = g_hash_table_lookup(fd->modified_xmp, key);
+		if (list) return string_list_copy(list);
 		}
 
-	if (keywords)
+	/* 
+	    Legacy metadata file is the primary source if it exists.
+	    Merging the lists does not make much sense, because the existence of
+	    legacy metadata file indicates that the other metadata sources are not
+	    writable and thus it would not be possible to delete the keywords
+	    that comes from the image file.
+	*/
+	if (strcmp(key, KEYWORD_KEY) == 0)
 		{
-		ExifItem *item;
-		guint i;
-		
-		*keywords = NULL;
-		item = exif_get_item(exif, KEYWORD_KEY);
-		for (i = 0; i < exif_item_get_elements(item); i++)
-			{
-			gchar *kw = exif_item_get_string(item, i);
-			gchar *utf8_kw;
-
-			if (!kw) break;
-
-			utf8_kw = utf8_validate_or_convert(kw);
-			*keywords = g_list_append(*keywords, (gpointer) utf8_kw);
-			g_free(kw);
-			}
+	        if (metadata_legacy_read(fd, &list, NULL)) return list;
+	        }
 
-		/* FIXME:
-		 * Exiv2 handles Iptc keywords as multiple entries with the
-		 * same key, thus exif_get_item returns only the first keyword
-		 * and the only way to get all keywords is to iterate through
-		 * the item list.
-		 */
-		 /* Read IPTC keywords only if there are no XMP keywords
-		  * IPTC does not have standard charset, thus the encoding may differ
-		  * from XMP and keyword merging is not reliable.
-		  */
-		 if (!*keywords)
-			{
-			for (item = exif_get_first_item(exif);
-			     item;
-			     item = exif_get_next_item(exif))
-				{
-				guint tag;
-			
-				tag = exif_item_get_tag_id(item);
-				if (tag == 0x0019)
-					{
-					gchar *tag_name = exif_item_get_tag_name(item);
-        
-					if (strcmp(tag_name, "Iptc.Application2.Keywords") == 0)
-						{
-						gchar *kw;
-						gchar *utf8_kw;
-        
-						kw = exif_item_get_data_as_text(item);
-						if (!kw) continue;
-        
-						utf8_kw = utf8_validate_or_convert(kw);
-						*keywords = g_list_append(*keywords, (gpointer) utf8_kw);
-						g_free(kw);
-						}
-					g_free(tag_name);
-					}
-				}
-			}
-		}
-
+	if (strcmp(key, COMMENT_KEY) == 0)
+		{
+		gchar *comment = NULL;
+	        if (metadata_legacy_read(fd, NULL, &comment)) return g_list_append(NULL, comment);
+	        }
+	
+	exif = exif_read_fd(fd); /* this is cached, thus inexpensive */
+	if (!exif) return NULL;
+	list = exif_get_metadata(exif, key);
 	exif_free_fd(fd, exif);
-
-	return (comment && *comment) || (keywords && *keywords);
+	return list;
 }
 
-gint metadata_read(FileData *fd, GList **keywords, gchar **comment)
+gchar *metadata_read_string(FileData *fd, const gchar *key)
 {
-	GList *keywords_xmp = NULL;
-	GList *keywords_legacy = NULL;
-	gchar *comment_xmp = NULL;
-	gchar *comment_legacy = NULL;
-	gint result_xmp, result_legacy;
-
-	if (!fd) return FALSE;
-
-	result_xmp = metadata_xmp_read(fd, &keywords_xmp, &comment_xmp);
-	result_legacy = metadata_legacy_read(fd, &keywords_legacy, &comment_legacy);
-
-	if (!result_xmp && !result_legacy)
+	GList *string_list = metadata_read_list(fd, key);
+	if (string_list)
 		{
-		return FALSE;
+		gchar *str = string_list->data;
+		string_list->data = NULL;
+		string_list_free(string_list);
+		return str;
 		}
-
-	if (keywords)
+	return NULL;
+}
+	
+gboolean metadata_append_string(FileData *fd, const gchar *key, const char *value)
+{
+	gchar *str = metadata_read_string(fd, key);
+	
+	if (!str) 
 		{
-		if (result_xmp && result_legacy)
-			*keywords = g_list_concat(keywords_xmp, keywords_legacy);
-		else
-			*keywords = result_xmp ? keywords_xmp : keywords_legacy;
-
-		*keywords = remove_duplicate_strings_from_list(*keywords);
+		return metadata_write_string(fd, key, value);
 		}
 	else
 		{
-		if (result_xmp) string_list_free(keywords_xmp);
-		if (result_legacy) string_list_free(keywords_legacy);
-		}
-
-
-	if (comment)
-		{
-		if (result_xmp && result_legacy && comment_xmp && comment_legacy && *comment_xmp && *comment_legacy)
-			*comment = g_strdup_printf("%s\n%s", comment_xmp, comment_legacy);
-		else
-			*comment = result_xmp ? comment_xmp : comment_legacy;
+		gchar *new_string = g_strconcat(str, value, NULL);
+		gboolean ret = metadata_write_string(fd, key, new_string);
+		g_free(str);
+		g_free(new_string);
+		return ret;
 		}
-
-	if (result_xmp && (!comment || *comment != comment_xmp)) g_free(comment_xmp);
-	if (result_legacy && (!comment || *comment != comment_legacy)) g_free(comment_legacy);
-	
-	// return FALSE in the following cases:
-	//  - only looking for a comment and didn't find one
-	//  - only looking for keywords and didn't find any
-	//  - looking for either a comment or keywords, but found nothing
-	if ((!keywords && comment   && !*comment)  ||
-	    (!comment  && keywords  && !*keywords) ||
-	    ( comment  && !*comment &&   keywords && !*keywords))
-		return FALSE;
-
-	return TRUE;
 }
 
-void metadata_set(FileData *fd, GList *new_keywords, gchar *new_comment, gboolean append)
+gboolean metadata_append_list(FileData *fd, const gchar *key, const GList *values)
 {
-	gchar *comment = NULL;
-	GList *keywords = NULL;
-	GList *keywords_list = NULL;
-
-	metadata_read(fd, &keywords, &comment);
+	GList *list = metadata_read_list(fd, key);
 	
-	if (new_comment)
-		{
-		if (append && comment && *comment)
-			{
-			gchar *tmp = comment;
-				
-			comment = g_strconcat(tmp, new_comment, NULL);
-			g_free(tmp);
-			}
-		else
-			{
-			g_free(comment);
-			comment = g_strdup(new_comment);
-			}
-		}
-	
-	if (new_keywords)
+	if (!list) 
 		{
-		if (append && keywords && g_list_length(keywords) > 0)
-			{
-			GList *work;
-
-			work = new_keywords;
-			while (work)
-				{
-				gchar *key;
-				GList *p;
-
-				key = work->data;
-				work = work->next;
-
-				p = keywords;
-				while (p && key)
-					{
-					gchar *needle = p->data;
-					p = p->next;
-
-					if (strcmp(needle, key) == 0) key = NULL;
-					}
-
-				if (key) keywords = g_list_append(keywords, g_strdup(key));
-				}
-			keywords_list = keywords;
-			}
-		else
-			{
-			keywords_list = new_keywords;
-			}
+		return metadata_write_list(fd, key, values);
 		}
-	
-	metadata_write_string(fd, COMMENT_KEY, comment);
-	metadata_write_list(fd, KEYWORD_KEY, keywords);
-
-	string_list_free(keywords);
-	g_free(comment);
+	else
+		{
+		gboolean ret;
+		list = g_list_concat(list, string_list_copy(values));
+		list = remove_duplicate_strings_from_list(list);
+		
+		ret = metadata_write_list(fd, key, list);
+		string_list_free(list);
+		return ret;
+		}
 }
 
 gboolean find_string_in_list(GList *list, const gchar *string)
@@ -687,7 +579,8 @@
 {
 	GList *keywords;
 	gboolean found = FALSE;
-	if (metadata_read(fd, &keywords, NULL))
+	keywords = metadata_read_list(fd, KEYWORD_KEY);
+	if (keywords)
 		{
 		GList *work = keywords;
 
@@ -713,7 +606,7 @@
 	gboolean found = FALSE;
 	gboolean changed = FALSE;
 	GList *work;
-	metadata_read(fd, &keywords, NULL);
+	keywords = metadata_read_list(fd, KEYWORD_KEY);
 
 	work = keywords;
 
--- a/src/metadata.h	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/metadata.h	Sat Jan 10 20:40:37 2009 +0000
@@ -27,9 +27,12 @@
 gboolean metadata_write_list(FileData *fd, const gchar *key, const GList *values);
 gboolean metadata_write_string(FileData *fd, const gchar *key, const char *value);
 
-gint metadata_read(FileData *fd, GList **keywords, gchar **comment);
+GList *metadata_read_list(FileData *fd, const gchar *key);
+gchar *metadata_read_string(FileData *fd, const gchar *key);
 
-void metadata_set(FileData *fd, GList *new_keywords, gchar *new_comment, gboolean append);
+gboolean metadata_append_string(FileData *fd, const gchar *key, const char *value);
+gboolean metadata_append_list(FileData *fd, const gchar *key, const GList *values);
+
 gboolean find_string_in_list(GList *list, const gchar *keyword);
 GList *string_to_keywords_list(const gchar *text);
 
--- a/src/search.c	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/search.c	Sat Jan 10 20:40:37 2009 +0000
@@ -1804,7 +1804,9 @@
 		tested = TRUE;
 		match = FALSE;
 
-		if (metadata_read(fd, &list, NULL))
+		list = metadata_read_list(fd, KEYWORD_KEY);
+
+		if (list)
 			{
 			GList *needle;
 			GList *haystack;
@@ -1882,7 +1884,9 @@
 		tested = TRUE;
 		match = FALSE;
 
-		if (metadata_read(fd, NULL, &comment))
+		comment = metadata_read_string(fd, COMMENT_KEY);
+
+		if (comment)
 			{
 			if (! sd->search_comment_match_case)
 				{
--- a/src/ui_fileops.c	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/ui_fileops.c	Sat Jan 10 20:40:37 2009 +0000
@@ -656,7 +656,7 @@
 	g_list_free(list);
 }
 
-GList *string_list_copy(GList *list)
+GList *string_list_copy(const GList *list)
 {
 	GList *new_list = NULL;
 	GList *work;
--- a/src/ui_fileops.h	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/ui_fileops.h	Sat Jan 10 20:40:37 2009 +0000
@@ -69,7 +69,7 @@
  * the lists with string_list_free()
  */
 void string_list_free(GList *list);
-GList *string_list_copy(GList *list);
+GList *string_list_copy(const GList *list);
 
 gchar *unique_filename(const gchar *path, const gchar *ext, const gchar *divider, gint pad);
 gchar *unique_filename_simple(const gchar *path);
--- a/src/view_file_icon.c	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/view_file_icon.c	Sat Jan 10 20:40:37 2009 +0000
@@ -568,7 +568,7 @@
 			gchar *str = g_strndup(selection->data, selection->length);
 			GList *kw_list = string_to_keywords_list(str);
 			
-			metadata_set(fd, kw_list, NULL, TRUE);
+			metadata_append_list(fd, KEYWORD_KEY, kw_list);
 			string_list_free(kw_list);
 			g_free(str);
 			if (vf->layout && vf->layout->bar_info) {
--- a/src/view_file_list.c	Sun Jan 04 17:14:34 2009 +0000
+++ b/src/view_file_list.c	Sat Jan 10 20:40:37 2009 +0000
@@ -323,7 +323,7 @@
 			gchar *str = g_strndup(selection->data, selection->length);
 			GList *kw_list = string_to_keywords_list(str);
 			
-			metadata_set(fd, kw_list, NULL, TRUE);
+			metadata_append_list(fd, KEYWORD_KEY, kw_list);
 			string_list_free(kw_list);
 			g_free(str);
 			if (vf->layout && vf->layout->bar_info) {