Fix #147: Alternative format for sidecar extension
authorTomasz Golinski <tomaszg@math.uwb.edu.pl>
Wed, 15 Mar 2017 11:06:10 +0000 (11:06 +0000)
committerColin Clark <cclark@mcb.net>
Wed, 15 Mar 2017 11:06:10 +0000 (11:06 +0000)
https://github.com/BestImageViewer/geeqie/issues/147

Add option to store sidecar extension with a format e.g. filename.jpg.xmp rather than filename.xmp

12 files changed:
doc/docbook/GuideOptionsMetadata.xml
src/filedata.c
src/metadata.c
src/options.c
src/options.h
src/preferences.c
src/print.c
src/rcfile.c
src/typedefs.h
src/ui_fileops.c
src/ui_fileops.h
src/utilops.c

index 2a315a6..5844eaa 100644 (file)
           If checked, open a confirmation dialogue before writing to the file\r
         </para>\r
       </listitem>\r
+      <listitem>\r
+        <para>\r
+          <guilabel>Create sidecar files named image.ext.xmp (as opposed to image.xmp)</guilabel>\r
+          <para />\r
+          If checked, new sidecar files will use image.ext.xmp naming scheme\r
+        </para>\r
+      </listitem>\r
     </itemizedlist>\r
   </section>\r
   <section id="WriteToGeeqiePrivateFiles">\r
index 34b545a..3126a4e 100644 (file)
@@ -605,6 +605,7 @@ static void file_data_free(FileData *fd)
        g_free(fd->original_path);
        g_free(fd->collate_key_name);
        g_free(fd->collate_key_name_nocase);
+       g_free(fd->extended_extension);
        if (fd->thumb_pixbuf) g_object_unref(fd->thumb_pixbuf);
        histmap_free(fd->histmap);
 
@@ -932,6 +933,8 @@ static void file_data_disconnect_sidecar_file(FileData *target, FileData *sfd)
 
        target->sidecar_files = g_list_remove(target->sidecar_files, sfd);
        sfd->parent = NULL;
+       g_free(sfd->extended_extension);
+       sfd->extended_extension = NULL;
 
        file_data_unref(target);
        file_data_unref(sfd);
@@ -1119,6 +1122,37 @@ static GList * file_data_basename_hash_insert(GHashTable *basename_hash, FileDat
 
        list = g_hash_table_lookup(basename_hash, basename);
 
+       if (!list)
+               {
+               DEBUG_1("TG: basename_hash not found for %s",fd->path);
+               const gchar *parent_extension = registered_extension_from_path(basename);
+
+               if (parent_extension)
+                       {
+                       DEBUG_1("TG: parent extension %s",parent_extension);
+                       gchar *parent_basename = g_strndup(basename, parent_extension - basename);
+                       DEBUG_1("TG: parent basename %s",parent_basename);
+                       FileData *parent_fd = g_hash_table_lookup(file_data_pool, basename);
+                       if (parent_fd)
+                               {
+                               DEBUG_1("TG: parent fd found");
+                               list = g_hash_table_lookup(basename_hash, parent_basename);
+                               if (!g_list_find(list, parent_fd))
+                                       {
+                                       DEBUG_1("TG: parent fd doesn't fit");
+                                       g_free(parent_basename);
+                                       list = NULL;
+                                       }
+                               else
+                                       {
+                                       g_free(basename);
+                                       basename = parent_basename;
+                                       fd->extended_extension = g_strconcat(parent_extension, fd->extension, NULL);
+                                       }
+                               }
+                       }
+               }
+
        if (!g_list_find(list, fd))
                {
                list = g_list_insert_sorted(list, file_data_ref(fd), file_data_sort_by_ext);
@@ -1131,6 +1165,11 @@ static GList * file_data_basename_hash_insert(GHashTable *basename_hash, FileDat
        return list;
 }
 
+static void file_data_basename_hash_insert_cb(gpointer fd, gpointer basename_hash)
+{
+       file_data_basename_hash_insert((GHashTable *)basename_hash, (FileData *)fd);
+}
+
 static void file_data_basename_hash_remove_list(gpointer key, gpointer value, gpointer data)
 {
        filelist_free((GList *)value);
@@ -1195,6 +1234,7 @@ static gboolean filelist_read_real(const gchar *dir_path, GList **files, GList *
        gchar *pathl;
        GList *dlist = NULL;
        GList *flist = NULL;
+       GList *xmp_files = NULL;
        gint (*stat_func)(const gchar *path, struct stat *buf);
        GHashTable *basename_hash = NULL;
 
@@ -1252,7 +1292,10 @@ static gboolean filelist_read_real(const gchar *dir_path, GList **files, GList *
                                        flist = g_list_prepend(flist, fd);
                                        if (fd->sidecar_priority && !fd->disable_grouping)
                                                {
-                                               file_data_basename_hash_insert(basename_hash, fd);
+                                               if (strcmp(fd->extension, ".xmp") != 0)
+                                                       file_data_basename_hash_insert(basename_hash, fd);
+                                               else
+                                                       xmp_files = g_list_append(xmp_files, fd);
                                                }
                                        }
                                }
@@ -1271,6 +1314,12 @@ static gboolean filelist_read_real(const gchar *dir_path, GList **files, GList *
 
        g_free(pathl);
 
+       if (xmp_files)
+               {
+               g_list_foreach(xmp_files,file_data_basename_hash_insert_cb,basename_hash);
+               g_list_free(xmp_files);
+               }
+
        if (dirs) *dirs = dlist;
 
        if (files)
@@ -1531,22 +1580,29 @@ gchar *file_data_get_sidecar_path(FileData *fd, gboolean existing_only)
        if (!file_data_can_write_sidecar(fd)) return NULL;
 
        work = fd->parent ? fd->parent->sidecar_files : fd->sidecar_files;
+       gchar *extended_extension = g_strconcat(fd->parent ? fd->parent->extension : fd->extension, ".xmp", NULL);
        while (work)
                {
                FileData *sfd = work->data;
                work = work->next;
-               if (g_ascii_strcasecmp(sfd->extension, ".xmp") == 0)
+               if (g_ascii_strcasecmp(sfd->extension, ".xmp") == 0 || g_ascii_strcasecmp(sfd->extension, extended_extension) == 0)
                        {
                        sidecar_path = g_strdup(sfd->path);
                        break;
                        }
                }
+       g_free(extended_extension);
 
        if (!existing_only && !sidecar_path)
                {
-               gchar *base = g_strndup(fd->path, fd->extension - fd->path);
-               sidecar_path = g_strconcat(base, ".xmp", NULL);
-               g_free(base);
+               if (options->metadata.sidecar_extended_name)
+                       sidecar_path = g_strconcat(fd->path, ".xmp", NULL);
+               else
+                       {
+                       gchar *base = g_strndup(fd->path, fd->extension - fd->path);
+                       sidecar_path = g_strconcat(base, ".xmp", NULL);
+                       g_free(base);
+                       }
                }
 
        return sidecar_path;
@@ -2095,11 +2151,11 @@ static void file_data_update_ci_dest(FileData *fd, const gchar *dest_path)
 
 static void file_data_update_ci_dest_preserve_ext(FileData *fd, const gchar *dest_path)
 {
-       const gchar *extension = extension_from_path(fd->change->source);
+       const gchar *extension = registered_extension_from_path(fd->change->source);
        gchar *base = remove_extension_from_path(dest_path);
        gchar *old_path = fd->change->dest;
 
-       fd->change->dest = g_strconcat(base, extension, NULL);
+       fd->change->dest = g_strconcat(base, fd->extended_extension ? fd->extended_extension : extension, NULL);
        file_data_update_planned_change_hash(fd, old_path, fd->change->dest);
 
        g_free(old_path);
@@ -2372,7 +2428,7 @@ gint file_data_verify_ci(FileData *fd, GList *list)
 
                if (!same)
                        {
-                       const gchar *dest_ext = extension_from_path(fd->change->dest);
+                       const gchar *dest_ext = registered_extension_from_path(fd->change->dest);
                        if (!dest_ext) dest_ext = "";
                        if (!options->file_filter.disable_file_extension_checks)
                                {
index 721f12a..8c8e9ab 100644 (file)
@@ -302,7 +302,7 @@ gboolean metadata_write_perform(FileData *fd)
        g_assert(fd->change);
 
        if (fd->change->dest &&
-           strcmp(extension_from_path(fd->change->dest), GQ_CACHE_EXT_METADATA) == 0)
+           strcmp(registered_extension_from_path(fd->change->dest), GQ_CACHE_EXT_METADATA) == 0)
                {
                success = metadata_legacy_write(fd);
                if (success) metadata_legacy_delete(fd, fd->change->dest);
index c49396b..0cdb936 100644 (file)
@@ -131,6 +131,7 @@ ConfOptions *init_options(ConfOptions *options)
        options->metadata.confirm_on_dir_change = TRUE;
        options->metadata.keywords_case_sensitive = FALSE;
        options->metadata.write_orientation = TRUE;
+       options->metadata.sidecar_extended_name = FALSE;
 
        options->show_icon_names = TRUE;
 
index 9423679..43a41d4 100644 (file)
@@ -210,6 +210,7 @@ struct _ConfOptions
                gboolean confirm_on_dir_change;
                gboolean keywords_case_sensitive;
                gboolean write_orientation;
+               gboolean sidecar_extended_name;
        } metadata;
 
        /* Stereo */
index 669fb73..fce03ad 100644 (file)
@@ -334,6 +334,7 @@ static void config_window_apply(void)
        options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
        options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
        options->metadata.confirm_write = c_options->metadata.confirm_write;
+       options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
        options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
        options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
        options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
@@ -1908,6 +1909,9 @@ static void config_tab_metadata(GtkWidget *notebook)
        pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
                              options->metadata.confirm_write, &c_options->metadata.confirm_write);
 
+       pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
+                             options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
+
        group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
 #ifndef HAVE_EXIV2
        gtk_widget_set_sensitive(group, FALSE);
index bd61835..539ce64 100644 (file)
@@ -23,6 +23,7 @@
 #include "print.h"
 
 #include "filedata.h"
+#include "filefilter.h"
 #include "image.h"
 #include "image-load.h"
 #include "pixbuf_util.h"
@@ -1449,7 +1450,7 @@ static gboolean print_job_rgb_page_new(PrintWindow *pw, gint page)
                const gchar *ext;
                gchar *base;
 
-               ext = extension_from_path(pw->output_path);
+               ext = registered_extension_from_path(pw->output_path);
 
                if (ext)
                        {
index c86bf46..834a9a9 100644 (file)
@@ -442,6 +442,7 @@ static void write_global_attributes(GString *outstr, gint indent)
        WRITE_NL(); WRITE_BOOL(*options, metadata.save_legacy_format);
        WRITE_NL(); WRITE_BOOL(*options, metadata.sync_grouped_files);
        WRITE_NL(); WRITE_BOOL(*options, metadata.confirm_write);
+       WRITE_NL(); WRITE_BOOL(*options, metadata.sidecar_extended_name);
        WRITE_NL(); WRITE_INT(*options, metadata.confirm_timeout);
        WRITE_NL(); WRITE_BOOL(*options, metadata.confirm_after_timeout);
        WRITE_NL(); WRITE_BOOL(*options, metadata.confirm_on_image_change);
@@ -720,6 +721,7 @@ static gboolean load_global_params(const gchar **attribute_names, const gchar **
                if (READ_BOOL(*options, metadata.save_legacy_format)) continue;
                if (READ_BOOL(*options, metadata.sync_grouped_files)) continue;
                if (READ_BOOL(*options, metadata.confirm_write)) continue;
+               if (READ_BOOL(*options, metadata.sidecar_extended_name)) continue;
                if (READ_BOOL(*options, metadata.confirm_after_timeout)) continue;
                if (READ_INT(*options, metadata.confirm_timeout)) continue;
                if (READ_BOOL(*options, metadata.confirm_on_image_change)) continue;
index 11e1e99..ed553e1 100644 (file)
@@ -536,6 +536,7 @@ struct _FileData {
        gchar *path;
        const gchar *name;
        const gchar *extension;
+       gchar *extended_extension;
        gchar *collate_key_name;
        gchar *collate_key_name_nocase;
        gint64 size;
index c75ead5..714efc8 100644 (file)
@@ -41,6 +41,7 @@
 #include "ui_utildlg.h"        /* for locale warning dialog */
 #include "md5-util.h"
 
+#include "filefilter.h"
 /*
  *-----------------------------------------------------------------------------
  * generic file information and manipulation routines (public)
@@ -697,7 +698,7 @@ gchar *unique_filename_simple(const gchar *path)
        name = filename_from_path(path);
        if (!name) return NULL;
 
-       ext = extension_from_path(name);
+       ext = registered_extension_from_path(name);
 
        if (!ext)
                {
@@ -729,24 +730,14 @@ const gchar *filename_from_path(const gchar *path)
 
 gchar *remove_level_from_path(const gchar *path)
 {
-       gint p = 0, n = -1;
+       const gchar *base;
 
        if (!path) return NULL;
 
-       while (path[p])
-               {
-               if (path[p] == G_DIR_SEPARATOR) n = p;
-               p++;
-               }
-       if (n <= 0) n++;
+       base = strrchr(path, G_DIR_SEPARATOR);
+       if (base) return g_strndup(path, strlen(path)-strlen(base));
 
-       return g_strndup(path, (gsize) n);
-}
-
-const gchar *extension_from_path(const gchar *path)
-{
-       if (!path) return NULL;
-       return strrchr(path, '.');
+       return NULL;
 }
 
 gboolean file_extension_match(const gchar *path, const gchar *ext)
@@ -766,18 +757,8 @@ gboolean file_extension_match(const gchar *path, const gchar *ext)
 
 gchar *remove_extension_from_path(const gchar *path)
 {
-       gint p = 0, n = -1;
-
        if (!path) return NULL;
-
-       while (path[p])
-               {
-               if (path[p] == '.') n = p;
-               p++;
-               }
-       if (n < 0) n = p;
-
-       return g_strndup(path, (gsize) n);
+       return g_strndup(path, strlen(path)-strlen(registered_extension_from_path(path)));
 }
 
 void parse_out_relatives(gchar *path)
index eb25885..8f30502 100644 (file)
@@ -91,7 +91,6 @@ gchar *unique_filename_simple(const gchar *path);
 const gchar *filename_from_path(const gchar *path);
 gchar *remove_level_from_path(const gchar *path);
 
-const gchar *extension_from_path(const gchar *path);
 gchar *remove_extension_from_path(const gchar *path);
 
 gboolean file_extension_match(const gchar *path, const gchar *ext);
index 599244e..4b042b6 100644 (file)
@@ -225,7 +225,7 @@ static gint filename_base_length(const gchar *name)
                {
                const gchar *ext;
 
-               ext = extension_from_path(name);
+               ext = registered_extension_from_path(name);
                if (ext) n -= strlen(ext);
                }
 
@@ -1205,7 +1205,7 @@ static gchar *file_util_rename_multiple_auto_format_name(const gchar *format, co
                parsed = tmp;
                }
 
-       ext = extension_from_path(name);
+       ext = registered_extension_from_path(name);
 
        middle = strchr(parsed, '*');
        if (middle)