[shotwell: 1/3] Closes: https://gitlab.gnome.org/GNOME/shotwell/-/issues/92




commit 0c92be2913f4fb43492536aed6f53407ec1f9ef8
Author: maf <maf tkrat org>
Date:   Mon Jul 25 11:39:14 2022 +0200

    Closes: https://gitlab.gnome.org/GNOME/shotwell/-/issues/92

 src/AppWindow.vala | 13 +++++-----
 src/Exporter.vala  | 74 +++++++++++++++++++++++++++++++++++++++---------------
 src/util/file.vala |  8 ++++--
 3 files changed, 66 insertions(+), 29 deletions(-)
---
diff --git a/src/AppWindow.vala b/src/AppWindow.vala
index 608d1807..130f5e03 100644
--- a/src/AppWindow.vala
+++ b/src/AppWindow.vala
@@ -541,22 +541,21 @@ public abstract class AppWindow : PageWindow {
         return (Gtk.ResponseType) response;
     }
     
-    public static Gtk.ResponseType negate_affirm_all_cancel_question(string message, 
-        string negative, string affirmative, string affirmative_all, string? title = null,
-        Gtk.Window? parent = null) {
+       public static int six_alt_question(string message,
+               string alt1, string alt2, string alt3, string alt4, string alt5, string alt6,
+        string? title = null, Gtk.Window? parent = null) {
         Gtk.MessageDialog dialog = new Gtk.MessageDialog((parent != null) ? parent : get_instance(),
             Gtk.DialogFlags.MODAL, Gtk.MessageType.QUESTION, Gtk.ButtonsType.NONE, "%s", message);
         dialog.title = (title != null) ? title : Resources.APP_TITLE;
-        dialog.add_buttons(negative, Gtk.ResponseType.NO, affirmative, Gtk.ResponseType.YES,
-            affirmative_all, Gtk.ResponseType.APPLY,  _("_Cancel"), Gtk.ResponseType.CANCEL);
+        dialog.add_buttons(alt1, 1, alt2, 2, alt3, 3, alt4, 4, alt5, 5, alt6, 6);
         
         int response = dialog.run();
         
         dialog.destroy();
         
-        return (Gtk.ResponseType) response;
+        return response;
     }
-    
+
     public static void database_error(DatabaseError err) {
         panic(_("A fatal error occurred when accessing Shotwell’s library. Shotwell cannot 
continue.\n\n%s").printf(
             err.message));
diff --git a/src/Exporter.vala b/src/Exporter.vala
index b9596f5d..6b47fe97 100644
--- a/src/Exporter.vala
+++ b/src/Exporter.vala
@@ -55,7 +55,9 @@ public class Exporter : Object {
         YES,
         NO,
         CANCEL,
-        REPLACE_ALL
+        REPLACE_ALL,
+        RENAME,
+        RENAME_ALL,
     }
     
     public delegate void CompletionCallback(Exporter exporter, bool is_cancelled);
@@ -116,6 +118,7 @@ public class Exporter : Object {
     private unowned ProgressMonitor? monitor = null;
     private Cancellable cancellable;
     private bool replace_all = false;
+    private bool rename_all = false;
     private bool aborted = false;
     private ExportFormatParameters export_params;
 
@@ -193,6 +196,7 @@ public class Exporter : Object {
     
     private bool process_queue() {
         int submitted = 0;
+        Gee.HashSet<string> used = new Gee.HashSet<string>();
         foreach (MediaSource source in to_export) {
             File? use_source_file = null;
             PhotoFileFormat real_export_format = PhotoFileFormat.get_system_default_format();
@@ -227,7 +231,7 @@ public class Exporter : Object {
             if (export_dir == null) {
                 try {
                     bool collision;
-                    dest = generate_unique_file(AppDirs.get_temp_dir(), basename, out collision);
+                    dest = generate_unique_file(AppDirs.get_temp_dir(), basename, out collision, used);
                 } catch (Error err) {
                     AppWindow.error_message(_("Unable to generate a temporary file for %s: %s").printf(
                         source.get_file().get_basename(), err.message));
@@ -236,17 +240,30 @@ public class Exporter : Object {
                 }
             } else {
                 dest = dir.get_child(basename);
+                               bool rename = false;
                 
-                if (!replace_all && dest.query_exists(null)) {
-                    switch (overwrite_callback(this, dest)) {
+                if (!replace_all && (dest.query_exists(null) || used.contains(basename))) {
+                    if (rename_all) {
+                        rename = true;
+                    } else {
+                        switch (overwrite_callback(this, dest)) {
                         case Overwrite.YES:
                             // continue
-                        break;
+                            break;
                         
                         case Overwrite.REPLACE_ALL:
                             replace_all = true;
-                        break;
-                        
+                            break;
+
+                        case Overwrite.RENAME:
+                            rename = true;
+                            break;
+
+                        case Overwrite.RENAME_ALL:
+                            rename = true;
+                            rename_all = true;
+                            break;
+
                         case Overwrite.CANCEL:
                             cancellable.cancel();
                             
@@ -264,10 +281,22 @@ public class Exporter : Object {
                             }
                             
                             continue;
+                        }
+                    }
+                    if (rename) {
+                        try {
+                            bool collision;
+                            dest = generate_unique_file(dir, basename, out collision, used);
+                        } catch (Error err) {
+                            AppWindow.error_message(_("Unable to generate a temporary file for %s: 
%s").printf(
+                                                        source.get_file().get_basename(), err.message));
+                            break;
+                        }
                     }
                 }
             }
 
+            used.add(dest.get_basename());
             workers.enqueue(new ExportJob(this, source, dest, scaling, export_params.quality,
                 real_export_format, cancellable, export_params.mode == ExportFormatMode.UNMODIFIED, 
export_params.export_metadata));
             submitted++;
@@ -315,29 +344,34 @@ public class ExporterUI {
     private Exporter.Overwrite on_export_overwrite(Exporter exporter, File file) {
         progress_dialog.set_modal(false);
         string question = _("File %s already exists. Replace?").printf(file.get_basename());
-        Gtk.ResponseType response = AppWindow.negate_affirm_all_cancel_question(question, 
-            _("_Skip"), _("_Replace"), _("Replace _All"), _("Export"));
+        int response = AppWindow.six_alt_question(question, 
+                                                  _("_Skip"), _("Rename"), _("Rename All"),_("_Replace"), 
_("Replace _All"), _("_Cancel"), _("Export"));
         
         progress_dialog.set_modal(true);
 
         switch (response) {
-            case Gtk.ResponseType.APPLY:
-                return Exporter.Overwrite.REPLACE_ALL;
+        case 2:
+            return Exporter.Overwrite.RENAME;
             
-            case Gtk.ResponseType.YES:
-                return Exporter.Overwrite.YES;
+        case 3:
+            return Exporter.Overwrite.RENAME_ALL;
             
-            case Gtk.ResponseType.CANCEL:
-                return Exporter.Overwrite.CANCEL;
+        case 4:
+            return Exporter.Overwrite.YES;
             
-            case Gtk.ResponseType.NO:
-            default:
-                return Exporter.Overwrite.NO;
+        case 5:
+            return Exporter.Overwrite.REPLACE_ALL;
+            
+        case 6:
+            return Exporter.Overwrite.CANCEL;
+            
+        case 1:
+        default:
+            return Exporter.Overwrite.NO;
         }
     }
     
     private bool on_export_failed(Exporter exporter, File file, int remaining, Error err) {
         return export_error_dialog(file, remaining > 0) != Gtk.ResponseType.CANCEL;
     }
-}
-
+}
\ No newline at end of file
diff --git a/src/util/file.vala b/src/util/file.vala
index c6609d4c..838a0278 100644
--- a/src/util/file.vala
+++ b/src/util/file.vala
@@ -31,9 +31,11 @@ public bool claim_file(File file) throws Error {
 // same or similar as what has been requested (adds numerals to the end of the name until a unique
 // one has been found).  The file may exist when this function returns, and it should be
 // overwritten.  It does *not* attempt to create the parent directory, however.
+// The used parameter allows you to pass in a collection of names which should be deemed to be
+// already claimed but which may not yet exist in the file system.
 //
 // This function is thread-safe.
-public File? generate_unique_file(File dir, string basename, out bool collision) throws Error {
+public File? generate_unique_file(File dir, string basename, out bool collision, Gee.Collection<string>? 
used = null) throws Error {
     // create the file to atomically "claim" it
     File file = dir.get_child(basename);
     if (claim_file(file)) {
@@ -51,7 +53,9 @@ public File? generate_unique_file(File dir, string basename, out bool collision)
     // generate a unique filename
     for (int ctr = 1; ctr < int.MAX; ctr++) {
         string new_name = (ext != null) ? "%s_%d.%s".printf(name, ctr, ext) : "%s_%d".printf(name, ctr);
-        
+        if (used != null && used.contains(new_name)) {
+            continue;
+        }
         file = dir.get_child(new_name);
         if (claim_file(file))
             return file;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]