changeset 1211:e2bbe90b0dcd

most of the metadata options now works
author nadvornik
date Sun, 21 Dec 2008 21:20:36 +0000
parents cea120a73843
children 97f30a17dc6b
files src/cache_maint.c src/collect-io.c src/collect.c src/dupe.c src/exif-common.c src/exif.c src/exif.h src/exiv2.cc src/filedata.c src/img-view.c src/layout_image.c src/metadata.c src/metadata.h src/search.c src/utilops.c
diffstat 15 files changed, 247 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/src/cache_maint.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/cache_maint.c	Sun Dec 21 21:20:36 2008 +0000
@@ -636,6 +636,7 @@
 			cache_maint_removed(fd);
 			break;
 		case FILEDATA_CHANGE_UNSPECIFIED:
+		case FILEDATA_CHANGE_WRITE_METADATA:
 			break;
 		}
 }
--- a/src/collect-io.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/collect-io.c	Sun Dec 21 21:20:36 2008 +0000
@@ -945,8 +945,8 @@
 			collect_manager_moved(fd);
 			break;
 		case FILEDATA_CHANGE_DELETE:
-			break;
 		case FILEDATA_CHANGE_UNSPECIFIED:
+		case FILEDATA_CHANGE_WRITE_METADATA:
 			break;
 		}
 
--- a/src/collect.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/collect.c	Sun Dec 21 21:20:36 2008 +0000
@@ -776,6 +776,7 @@
 			while (collection_remove(cd, fd));
 			break;
 		case FILEDATA_CHANGE_UNSPECIFIED:
+		case FILEDATA_CHANGE_WRITE_METADATA:
 			break;
 		}
 
--- a/src/dupe.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/dupe.c	Sun Dec 21 21:20:36 2008 +0000
@@ -3582,6 +3582,7 @@
 			while (dupe_item_remove_by_path(dw, fd->path));
 			break;
 		case FILEDATA_CHANGE_UNSPECIFIED:
+		case FILEDATA_CHANGE_WRITE_METADATA:
 			break;
 		}
 
--- a/src/exif-common.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/exif-common.c	Sun Dec 21 21:20:36 2008 +0000
@@ -631,20 +631,6 @@
 	return fd->exif;
 }
 
-gint exif_write_fd(FileData *fd)
-{
-	gint success;
-	ExifData *exif;
-	
-	/*  exif_read_fd can either use cached metadata which have fd->modified_xmp already applied 
-	                             or read metadata from file and apply fd->modified_xmp
-	    metadata are read also if the file was modified meanwhile */
-	exif = exif_read_fd(fd); 
-	if (!exif) return FALSE;
-	success = exif_write(exif); /* write modified metadata */
-	exif_free_fd(fd, exif);
-	return success;
-}
 
 void exif_free_fd(FileData *fd, ExifData *exif)
 {
--- a/src/exif.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/exif.c	Sun Dec 21 21:20:36 2008 +0000
@@ -1578,10 +1578,16 @@
 	fprintf(f, "----------------------------------------------------\n");
 }
 
-gint exif_write(ExifData *exif)
+gboolean exif_write(ExifData *exif)
 {
 	log_printf("Not compiled with EXIF write support");
-	return 0;
+	return FALSE;
+}
+
+gboolean exif_write_sidecar(ExifData *exif, gchar *path)
+{
+	log_printf("Not compiled with EXIF write support");
+	return FALSE;
 }
 
 
--- a/src/exif.h	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/exif.h	Sun Dec 21 21:20:36 2008 +0000
@@ -111,14 +111,16 @@
 
 ExifData *exif_read_fd(FileData *fd);
 void exif_free_fd(FileData *fd, ExifData *exif);
-gint exif_write_fd(FileData *fd);
 
 /* exif_read returns processed data (merged from image and sidecar, etc.)
    this function gives access to the original data from the image.
    original data are part of the processed data and should not be freed separately */
 ExifData *exif_get_original(ExifData *processed);
 
-gint exif_write(ExifData *exif);
+
+gboolean exif_write(ExifData *exif);
+gboolean exif_write_sidecar(ExifData *exif, gchar *path);
+
 void exif_free(ExifData *exif);
 
 gchar *exif_get_data_as_text(ExifData *exif, const gchar *key);
--- a/src/exiv2.cc	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/exiv2.cc	Sun Dec 21 21:20:36 2008 +0000
@@ -76,7 +76,7 @@
 	{
 	}
 	
-	virtual void writeMetadata()
+	virtual void writeMetadata(gchar *path = NULL)
 	{
 		g_critical("Unsupported method of writing metadata");
 	}
@@ -254,45 +254,35 @@
 		return imageData_;
 	}
 
-	virtual void writeMetadata()
+	virtual void writeMetadata(gchar *path = NULL)
 	{
 #if EXIV2_TEST_VERSION(0,17,0)
 		syncExifWithXmp(exifData_, xmpData_);
-		copyXmpToIptc(xmpData_, iptcData_); //FIXME it should be configurable
 #endif
-		if (sidecarData_) 
+		if (!path)
 			{
-			sidecarData_->image()->setXmpData(xmpData_);
-			//Exiv2 sidecar converts xmp to exif and iptc, we don't want it.
-			sidecarData_->image()->clearExifData();
-			sidecarData_->image()->clearIptcData();
-			sidecarData_->image()->writeMetadata();
-			}
+#if EXIV2_TEST_VERSION(0,17,0)
+			if (options->metadata.save_legacy_IPTC) copyXmpToIptc(xmpData_, iptcData_);
+#endif
+			imageData_->image()->setExifData(exifData_);
+			imageData_->image()->setIptcData(iptcData_);
+			imageData_->image()->setXmpData(xmpData_);
+			imageData_->image()->writeMetadata();
+			} 
 		else
 			{
-			try 	{
-				imageData_->image()->setExifData(exifData_);
-				imageData_->image()->setIptcData(iptcData_);
-				imageData_->image()->setXmpData(xmpData_);
-				imageData_->image()->writeMetadata();
-				} 
-			catch (Exiv2::AnyError& e) 
-				{
-				// can't write into the image, create sidecar
 #if EXIV2_TEST_VERSION(0,17,0)
-				gchar *base = remove_extension_from_path(imageData_->image()->io().path().c_str());
-				gchar *pathl = g_strconcat(base, ".xmp", NULL);
+			gchar *pathl = path_from_utf8(path);;
 
-				Exiv2::Image::AutoPtr sidecar = Exiv2::ImageFactory::create(Exiv2::ImageType::xmp, pathl);
+			Exiv2::Image::AutoPtr sidecar = Exiv2::ImageFactory::create(Exiv2::ImageType::xmp, pathl);
 				
-				g_free(base);
-				g_free(pathl);
-				
-				sidecarData_ = new _ExifDataOriginal(sidecar);
-				sidecarData_->image()->setXmpData(xmpData_);
-				sidecarData_->image()->writeMetadata();
+			g_free(pathl);
+
+			sidecar->setXmpData(xmpData_);
+			sidecar->writeMetadata();
+#else
+			throw Exiv2::Error(3, "xmp");
 #endif
-				}
 			}
 	}
 	
@@ -352,15 +342,27 @@
 	
 }
 
-int exif_write(ExifData *exif)
+gboolean exif_write(ExifData *exif)
 {
 	try {
 		exif->writeMetadata();
-		return 1;
+		return TRUE;
 	}
 	catch (Exiv2::AnyError& e) {
 		std::cout << "Caught Exiv2 exception '" << e << "'\n";
-		return 0;
+		return FALSE;
+	}
+}
+
+gboolean exif_write_sidecar(ExifData *exif, gchar *path)
+{
+	try {
+		exif->writeMetadata(path);
+		return TRUE;
+	}
+	catch (Exiv2::AnyError& e) {
+		std::cout << "Caught Exiv2 exception '" << e << "'\n";
+		return FALSE;
 	}
 	
 }
--- a/src/filedata.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/filedata.c	Sun Dec 21 21:20:36 2008 +0000
@@ -1122,7 +1122,6 @@
 }
 
 
-
 /*
  * file_data    - operates on the given fd
  * file_data_sc - operates on the given fd + sidecars - all fds linked via fd->sidecar_files or fd->parent
@@ -1638,7 +1637,8 @@
 		return ret;
 		}
 
-	if (!isname(fd->path))
+	if (!isname(fd->path) && 
+	    !filter_file_class(fd->extension, FORMAT_CLASS_META)) /* xmp sidecar can be eventually created from scratch */
 		{
 		/* this probably should not happen */
 		ret |= CHANGE_NO_SRC;
@@ -1649,6 +1649,7 @@
 	dir = remove_level_from_path(fd->path);
 	
 	if (fd->change->type != FILEDATA_CHANGE_DELETE &&
+	    fd->change->type != FILEDATA_CHANGE_WRITE_METADATA &&
 	    !access_file(fd->path, R_OK))
 		{
 		ret |= CHANGE_NO_READ_PERM;
@@ -1662,12 +1663,31 @@
 		}
 	else if (fd->change->type != FILEDATA_CHANGE_COPY &&
 		 fd->change->type != FILEDATA_CHANGE_UNSPECIFIED &&
+		 fd->change->type != FILEDATA_CHANGE_WRITE_METADATA &&
 		 !access_file(fd->path, W_OK))
 		{
 		ret |= CHANGE_WARN_NO_WRITE_PERM;
 		DEBUG_1("Change checked: no write permission: %s", fd->path);
 		}
-
+	/* WRITE_METADATA is special because it can be configured to silently write to ~/.geeqie/...
+	   - that means that there are no hard errors and warnings can be disabled
+	*/
+	else if (fd->change->type == FILEDATA_CHANGE_WRITE_METADATA && 
+	         options->metadata.save_in_image_file && options->metadata.warn_on_write_problems)
+		{
+		if (isname(fd->path) && !access_file(fd->path, W_OK))
+			{
+			ret |= CHANGE_WARN_NO_WRITE_PERM;
+			DEBUG_1("Change checked: file is readonly: %s", fd->path);
+			}
+		
+		else if (!access_file(dir, W_OK))
+			{
+			ret |= CHANGE_WARN_NO_WRITE_PERM;
+			DEBUG_1("Change checked: dir is readonly: %s", fd->path);
+			}
+		}
+		
 	if (fd->change->dest)
 		{
 		gboolean same;
--- a/src/img-view.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/img-view.c	Sun Dec 21 21:20:36 2008 +0000
@@ -1704,6 +1704,7 @@
 			view_real_removed(vw, fd);
 			break;
 		case FILEDATA_CHANGE_UNSPECIFIED:
+		case FILEDATA_CHANGE_WRITE_METADATA:
 			break;
 		}
 }
--- a/src/layout_image.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/layout_image.c	Sun Dec 21 21:20:36 2008 +0000
@@ -1812,6 +1812,7 @@
 			break;
 		case FILEDATA_CHANGE_COPY:
 		case FILEDATA_CHANGE_UNSPECIFIED:
+		case FILEDATA_CHANGE_WRITE_METADATA:
 			break;
 		}
 
--- a/src/metadata.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/metadata.c	Sun Dec 21 21:20:36 2008 +0000
@@ -22,6 +22,7 @@
 #include "ui_fileops.h"
 #include "ui_misc.h"
 #include "utilops.h"
+#include "filefilter.h"
 
 typedef enum {
 	MK_NONE,
@@ -37,6 +38,20 @@
 static gint metadata_legacy_delete(FileData *fd);
 
 
+
+gboolean metadata_can_write_directly(FileData *fd)
+{
+	return (filter_file_class(fd->extension, FORMAT_CLASS_IMAGE));
+/* FIXME: detect what exiv2 really supports */
+}
+
+gboolean metadata_can_write_sidecar(FileData *fd)
+{
+	return (filter_file_class(fd->extension, FORMAT_CLASS_RAWIMAGE));
+/* FIXME: detect what exiv2 really supports */
+}
+
+
 /*
  *-------------------------------------------------------------------
  * write queue
@@ -46,6 +61,60 @@
 static GList *metadata_write_queue = NULL;
 static gint metadata_write_idle_id = -1;
 
+static FileData *metadata_xmp_sidecar_fd(FileData *fd)
+{
+	GList *work;
+	gchar *base, *new_name;
+	FileData *ret;
+	
+	if (!metadata_can_write_sidecar(fd)) return NULL;
+		
+	
+	if (fd->parent) fd = fd->parent;
+	
+	if (filter_file_class(fd->extension, FORMAT_CLASS_META))
+		return file_data_ref(fd);
+	
+	work = fd->sidecar_files;
+	while (work)
+		{
+		FileData *sfd = work->data;
+		work = work->next;
+		if (filter_file_class(sfd->extension, FORMAT_CLASS_META))
+			return file_data_ref(sfd);
+		}
+	
+	/* sidecar does not exist yet */
+	base = remove_extension_from_path(fd->path);
+	new_name = g_strconcat(base, ".xmp", NULL);
+	g_free(base);
+	ret = file_data_new_simple(new_name);
+	g_free(new_name);
+	return ret;
+}
+
+static FileData *metadata_xmp_main_fd(FileData *fd)
+{
+	if (filter_file_class(fd->extension, FORMAT_CLASS_META) && !g_list_find(metadata_write_queue, fd))
+		{
+		/* fd is a sidecar, we have to find the original file */
+		
+		GList *work = metadata_write_queue;
+		while (work)
+			{
+			FileData *ofd = work->data;
+			FileData *osfd = metadata_xmp_sidecar_fd(ofd);
+			work = work->next;
+			file_data_unref(osfd);
+			if (fd == osfd)
+				{
+				return ofd; /* this is the main file */
+				}
+			}
+		}
+	return NULL;
+}
+
 
 static void metadata_write_queue_add(FileData *fd)
 {
@@ -60,39 +129,102 @@
 
 gboolean metadata_write_queue_remove(FileData *fd)
 {
+	FileData *main_fd = metadata_xmp_main_fd(fd);
+
+	if (main_fd) fd = main_fd;
+
 	g_hash_table_destroy(fd->modified_xmp);
 	fd->modified_xmp = NULL;
 
 	metadata_write_queue = g_list_remove(metadata_write_queue, fd);
+	
+	file_data_increment_version(fd);
+	file_data_send_notification(fd, NOTIFY_TYPE_REREAD);
+
 	file_data_unref(fd);
 	return TRUE;
 }
 
+gboolean metadata_write_queue_remove_list(GList *list)
+{
+	GList *work;
+	gboolean ret = TRUE;
+	
+	work = list;
+	while (work)
+		{
+		FileData *fd = work->data;
+		work = work->next;
+		ret = ret && metadata_write_queue_remove(fd);
+		}
+	return ret;
+}
+
 
 static gboolean metadata_write_queue_idle_cb(gpointer data)
 {
-	/* TODO:  the queue should not be passed to file_util_write_metadata directly:
-		  metatata under .geeqie/ can be written immediately, 
-	          for others we can decide if we write to the image file or to sidecar */
+	GList *work;
+	GList *to_approve = NULL;
 	
+	work = metadata_write_queue;
+	while (work)
+		{
+		FileData *fd = work->data;
+		work = work->next;
+		
+		if (fd->change) continue; /* another operation in progress, skip this file for now */
+		
+		FileData *to_approve_fd = metadata_xmp_sidecar_fd(fd);
+		
+		if (!to_approve_fd) to_approve_fd = file_data_ref(fd); /* this is not a sidecar */
 
-//	if (metadata_write_queue) return TRUE;
+		to_approve = g_list_prepend(to_approve, to_approve_fd);
+		}
 
-	/* confirm writting */
-	file_util_write_metadata(NULL, metadata_write_queue, NULL);
+	file_util_write_metadata(NULL, to_approve, NULL);
+	
+	filelist_free(to_approve);
 
 	metadata_write_idle_id = -1;
 	return FALSE;
 }
 
+gboolean metadata_write_exif(FileData *fd, FileData *sfd)
+{
+	gboolean success;
+	ExifData *exif;
+	
+	/*  we can either use cached metadata which have fd->modified_xmp already applied 
+	                             or read metadata from file and apply fd->modified_xmp
+	    metadata are read also if the file was modified meanwhile */
+	exif = exif_read_fd(fd); 
+	if (!exif) return FALSE;
+	success = sfd ? exif_write_sidecar(exif, sfd->path) : exif_write(exif); /* write modified metadata */
+	exif_free_fd(fd, exif);
+	return success;
+}
+
 gboolean metadata_write_perform(FileData *fd)
 {
+	FileData *sfd = NULL;
+	FileData *main_fd = metadata_xmp_main_fd(fd);
+
+	if (main_fd)
+		{
+		sfd = fd;
+		fd = main_fd;
+		}
+
 	if (options->metadata.save_in_image_file &&
-	    exif_write_fd(fd))
+	    metadata_write_exif(fd, sfd))
 		{
 		metadata_legacy_delete(fd);
+		if (sfd) metadata_legacy_delete(sfd);
 		}
-	else metadata_legacy_write(fd);
+	else
+		{
+		metadata_legacy_write(fd);
+		}
 	return TRUE;
 }
 
@@ -435,8 +567,23 @@
 	if (!fd) return FALSE;
 
 	if (write_comment) success = success && metadata_write_string(fd, COMMENT_KEY, comment);
+	if (keywords) success = success && metadata_write_list(fd, KEYWORD_KEY, string_list_copy(keywords));
 	
-	if (keywords) success = success && metadata_write_list(fd, KEYWORD_KEY, string_list_copy(keywords));
+	if (options->metadata.sync_grouped_files)
+		{
+		GList *work = fd->sidecar_files;
+		
+		while (work)
+			{
+			FileData *sfd = work->data;
+			work = work->next;
+			
+			if (filter_file_class(sfd->extension, FORMAT_CLASS_META)) continue; 
+
+			if (write_comment) success = success && metadata_write_string(sfd, COMMENT_KEY, comment);
+			if (keywords) success = success && metadata_write_list(sfd, KEYWORD_KEY, string_list_copy(keywords));
+			}
+		}
 
 	return success;
 }
--- a/src/metadata.h	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/metadata.h	Sun Dec 21 21:20:36 2008 +0000
@@ -14,6 +14,7 @@
 #ifndef METADATA_H
 #define METADATA_H
 gboolean metadata_write_queue_remove(FileData *fd);
+gboolean metadata_write_queue_remove_list(GList *list);
 gboolean metadata_write_perform(FileData *fd);
 
 
--- a/src/search.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/search.c	Sun Dec 21 21:20:36 2008 +0000
@@ -2955,6 +2955,7 @@
 			break;
 		case FILEDATA_CHANGE_COPY:
 		case FILEDATA_CHANGE_UNSPECIFIED:
+		case FILEDATA_CHANGE_WRITE_METADATA:
 			break;
 		}
 }
--- a/src/utilops.c	Sun Dec 21 16:26:03 2008 +0000
+++ b/src/utilops.c	Sun Dec 21 21:20:36 2008 +0000
@@ -402,7 +402,7 @@
 		}
 }
 
-static GtkWidget *file_util_dialog_add_list(GtkWidget *box, GList *list, gint full_paths)
+static GtkWidget *file_util_dialog_add_list(GtkWidget *box, GList *list, gint full_paths, gboolean with_sidecars)
 {
 	GtkWidget *scrolled;
 	GtkWidget *view;
@@ -443,7 +443,7 @@
 		GtkTreeIter iter;
 		gchar *sidecars;
 		
-		sidecars = file_data_sc_list_to_string(fd);
+		sidecars = with_sidecars ? file_data_sc_list_to_string(fd) : NULL;
 
 		gtk_list_store_append(store, &iter);
 		gtk_list_store_set(store, &iter,
@@ -1303,8 +1303,8 @@
 	
 	box = pref_group_new(box, TRUE, ud->messages.desc_flist, GTK_ORIENTATION_HORIZONTAL);
 
-	ud->listview = file_util_dialog_add_list(box, ud->flist, FALSE);
-	file_util_dialog_add_list_column(ud->listview, _("Sidecars"), FALSE, UTILITY_COLUMN_SIDECARS);
+	ud->listview = file_util_dialog_add_list(box, ud->flist, FALSE, ud->with_sidecars);
+	if (ud->with_sidecars) file_util_dialog_add_list_column(ud->listview, _("Sidecars"), FALSE, UTILITY_COLUMN_SIDECARS);
 
 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(ud->listview));
 	gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
@@ -1395,7 +1395,7 @@
 
 	box = pref_group_new(box, TRUE, ud->messages.desc_flist, GTK_ORIENTATION_HORIZONTAL);
 
-	ud->listview = file_util_dialog_add_list(box, ud->flist, FALSE);
+	ud->listview = file_util_dialog_add_list(box, ud->flist, FALSE, ud->with_sidecars);
 	file_util_dialog_add_list_column(ud->listview, _("Sidecars"), FALSE, UTILITY_COLUMN_SIDECARS);
 
 	file_util_dialog_add_list_column(ud->listview, _("New name"), FALSE, UTILITY_COLUMN_DEST_NAME);
@@ -1548,6 +1548,12 @@
 			break;
 		case UTILITY_PHASE_CANCEL:
 		case UTILITY_PHASE_DONE:
+
+			/* FIXME: put it here for now */
+			if (ud->type == UTILITY_TYPE_WRITE_METADATA)
+				{
+				metadata_write_queue_remove_list(ud->flist);
+				}
 			if (ud->with_sidecars)
 				file_data_sc_free_ci_list(ud->flist);
 			else
@@ -2051,7 +2057,7 @@
 		box = pref_group_new(box, TRUE, _("Subfolders:"), GTK_ORIENTATION_VERTICAL);
 
 		rlist = filelist_sort_path(rlist);
-		file_util_dialog_add_list(box, rlist, FALSE);
+		file_util_dialog_add_list(box, rlist, FALSE, FALSE);
 
 		gtk_widget_show(gd->dialog);
 		}
@@ -2261,7 +2267,8 @@
 
 void file_util_write_metadata(FileData *source_fd, GList *source_list, GtkWidget *parent)
 {
-	file_util_write_metadata_full(source_fd, source_list, parent, UTILITY_PHASE_START);
+	file_util_write_metadata_full(source_fd, source_list, parent, 
+	                              (options->metadata.save_in_image_file && options->metadata.confirm_write) ? UTILITY_PHASE_START : UTILITY_PHASE_ENTERING);
 }
 
 void file_util_copy(FileData *source_fd, GList *source_list, const gchar *dest_path, GtkWidget *parent)