most of the metadata options now works
authorVladimir Nadvornik <nadvornik@suse.cz>
Sun, 21 Dec 2008 21:20:36 +0000 (21:20 +0000)
committerVladimir Nadvornik <nadvornik@suse.cz>
Sun, 21 Dec 2008 21:20:36 +0000 (21:20 +0000)
15 files changed:
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

index 1c930ab..dbb344f 100644 (file)
@@ -636,6 +636,7 @@ void cache_notify_cb(FileData *fd, NotifyType type, gpointer data)
                        cache_maint_removed(fd);
                        break;
                case FILEDATA_CHANGE_UNSPECIFIED:
+               case FILEDATA_CHANGE_WRITE_METADATA:
                        break;
                }
 }
index b8d1b92..2820c7a 100644 (file)
@@ -945,8 +945,8 @@ void collect_manager_notify_cb(FileData *fd, NotifyType type, gpointer data)
                        collect_manager_moved(fd);
                        break;
                case FILEDATA_CHANGE_DELETE:
-                       break;
                case FILEDATA_CHANGE_UNSPECIFIED:
+               case FILEDATA_CHANGE_WRITE_METADATA:
                        break;
                }
 
index 9c2c255..a3be433 100644 (file)
@@ -776,6 +776,7 @@ static void collection_notify_cb(FileData *fd, NotifyType type, gpointer data)
                        while (collection_remove(cd, fd));
                        break;
                case FILEDATA_CHANGE_UNSPECIFIED:
+               case FILEDATA_CHANGE_WRITE_METADATA:
                        break;
                }
 
index 84b36df..1b85dc0 100644 (file)
@@ -3582,6 +3582,7 @@ static void dupe_notify_cb(FileData *fd, NotifyType type, gpointer data)
                        while (dupe_item_remove_by_path(dw, fd->path));
                        break;
                case FILEDATA_CHANGE_UNSPECIFIED:
+               case FILEDATA_CHANGE_WRITE_METADATA:
                        break;
                }
 
index b54f939..5966506 100644 (file)
@@ -631,20 +631,6 @@ ExifData *exif_read_fd(FileData *fd)
        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)
 {
index 35781b0..7ba5918 100644 (file)
@@ -1578,10 +1578,16 @@ void exif_write_data_list(ExifData *exif, FILE *f, gint human_readable_list)
        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;
 }
 
 
index e9c3c5a..2183b96 100644 (file)
@@ -111,14 +111,16 @@ ExifData *exif_read(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp);
 
 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);
index 27f4463..975e8be 100644 (file)
@@ -76,7 +76,7 @@ struct _ExifData
        {
        }
        
-       virtual void writeMetadata()
+       virtual void writeMetadata(gchar *path = NULL)
        {
                g_critical("Unsupported method of writing metadata");
        }
@@ -254,45 +254,35 @@ public:
                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 @@ ExifData *exif_read(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp)
        
 }
 
-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;
        }
        
 }
index ae10338..4aca86d 100644 (file)
@@ -1122,7 +1122,6 @@ void file_data_set_user_orientation(FileData *fd, gint value)
 }
 
 
-
 /*
  * 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 @@ gint file_data_verify_ci(FileData *fd)
                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 @@ gint file_data_verify_ci(FileData *fd)
        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 @@ gint file_data_verify_ci(FileData *fd)
                }
        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;
index e70ea88..95f755c 100644 (file)
@@ -1704,6 +1704,7 @@ static void view_window_notify_cb(FileData *fd, NotifyType type, gpointer data)
                        view_real_removed(vw, fd);
                        break;
                case FILEDATA_CHANGE_UNSPECIFIED:
+               case FILEDATA_CHANGE_WRITE_METADATA:
                        break;
                }
 }
index 15e4830..05051a3 100644 (file)
@@ -1812,6 +1812,7 @@ void layout_image_notify_cb(FileData *fd, NotifyType type, gpointer data)
                        break;
                case FILEDATA_CHANGE_COPY:
                case FILEDATA_CHANGE_UNSPECIFIED:
+               case FILEDATA_CHANGE_WRITE_METADATA:
                        break;
                }
 
index c6d6d89..36381ff 100644 (file)
@@ -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_write(FileData *fd);
 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 gint metadata_legacy_delete(FileData *fd);
 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 @@ static void metadata_write_queue_add(FileData *fd)
 
 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 @@ gint metadata_write(FileData *fd, GList *keywords, const gchar *comment)
        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 (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;
 }
index aca4262..79ce78d 100644 (file)
@@ -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);
 
 
index 8413ada..acd83c8 100644 (file)
@@ -2955,6 +2955,7 @@ static void search_notify_cb(FileData *fd, NotifyType type, gpointer data)
                        break;
                case FILEDATA_CHANGE_COPY:
                case FILEDATA_CHANGE_UNSPECIFIED:
+               case FILEDATA_CHANGE_WRITE_METADATA:
                        break;
                }
 }
index 970978b..ed42c3e 100644 (file)
@@ -402,7 +402,7 @@ static void file_util_dialog_list_select(GtkWidget *view, gint n)
                }
 }
 
-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 @@ static GtkWidget *file_util_dialog_add_list(GtkWidget *box, GList *list, gint fu
                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 @@ static void file_util_dialog_init_simple_list(UtilityData *ud)
        
        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 @@ static void file_util_dialog_init_source_dest(UtilityData *ud)
 
        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 @@ void file_util_dialog_run(UtilityData *ud)
                        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 @@ static void file_util_delete_dir_full(FileData *fd, GtkWidget *parent, UtilityPh
                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_delete(FileData *source_fd, GList *source_list, GtkWidget *parent
 
 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)