From 380d96407751668e80d20976843b1d5bfc9cf1b5 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sat, 6 Jan 2024 16:00:19 -0500 Subject: [PATCH 01/19] Add destination path preview label to batch queue panel. Label initially says "Destination path for the first selected image appears here" so the feature is discoverable. Select a file and it shows the destination path that would be used if it is the first file to be processed and the file does not already exist. Label is updated as the template is edited, so you can see the effect of the edits. If "Save to folder" is selected, the previewed path uses that folder. --- rtdata/languages/default | 2 ++ rtgui/batchqueue.cc | 40 ++++++++++++++++++++++++++++++++++++++++ rtgui/batchqueue.h | 3 +++ rtgui/batchqueuepanel.cc | 11 +++++++++++ rtgui/batchqueuepanel.h | 2 ++ 5 files changed, 58 insertions(+) diff --git a/rtdata/languages/default b/rtdata/languages/default index 403fccdf0..2f22b4642 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2101,6 +2101,8 @@ QINFO_PIXELSHIFT;Pixel Shift / %2 frame(s) QUEUE_AUTOSTART;Auto-start QUEUE_AUTOSTART_TOOLTIP;Start processing automatically when a new job arrives. QUEUE_DESTFILENAME;Path and file name +QUEUE_DESTPREVIEW_TITLE;Select a thumbnail to preview its destination path here +QUEUE_DESTPREVIEW_TOOLTIP;Destination path for the first selected image appears here QUEUE_FORMAT_TITLE;File Format QUEUE_LOCATION_FOLDER;Save to folder QUEUE_LOCATION_TEMPLATE;Use template diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 6ab75bd47..8d2ad176e 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -567,6 +567,41 @@ void BatchQueue::openLastSelectedItemInEditor() } } +void BatchQueue::updateDestinationPathPreview() +{ + MYWRITERLOCK(l, entryRW); + + if (selected.size()) + { + auto &entry = *selected.at(0); + int sequence = 0; // Sequence during subsequent queue processing can't be determined here + Glib::ustring baseDestination; + if (options.saveUsePathTemplate) + { + baseDestination = calcAutoFileNameBase(entry.filename, sequence); + } + else + { + Glib::ustring baseFilename; + int extpos = entry.filename.size() - 1; + for (; extpos >= 0 && entry.filename[extpos] != '.'; extpos--) + { + } + for (int k = extpos - 1; k >= 0 && entry.filename[k] != '/' && entry.filename[k] != '\\'; k--) + { + baseFilename = entry.filename[k] + baseFilename; + } + baseDestination = options.savePathFolder + '/' + baseFilename; + } + Glib::ustring destination = Glib::ustring::compose ("%1.%2", baseDestination, options.saveFormatBatch.format); + + if (listener) + { + listener->setDestinationPreviewText(destination); + } + } +} + void BatchQueue::openItemInEditor(ThumbBrowserEntryBase* item) { if (item) { @@ -1021,3 +1056,8 @@ void BatchQueue::redrawNeeded (LWButton* button) GThreadLock lock; queue_draw (); } + +void BatchQueue::selectionChanged() +{ + updateDestinationPathPreview(); +} diff --git a/rtgui/batchqueue.h b/rtgui/batchqueue.h index 5cde37748..f8f1cf255 100644 --- a/rtgui/batchqueue.h +++ b/rtgui/batchqueue.h @@ -38,6 +38,7 @@ public: virtual ~BatchQueueListener() = default; virtual void queueSizeChanged(int qsize, bool queueRunning, bool queueError, const Glib::ustring& queueErrorMessage) = 0; virtual bool canStartNext() = 0; + virtual void setDestinationPreviewText(const Glib::ustring& destinationPath) = 0; }; class FileCatalog; @@ -59,6 +60,7 @@ public: void selectAll (); void openItemInEditor(ThumbBrowserEntryBase* item); void openLastSelectedItemInEditor(); + void updateDestinationPathPreview(); void startProcessing (); @@ -79,6 +81,7 @@ public: bool keyPressed (GdkEventKey* event) override; void buttonPressed (LWButton* button, int actionCode, void* actionData) override; void redrawNeeded (LWButton* button) override; + void selectionChanged () override; void setBatchQueueListener (BatchQueueListener* l) { diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 8a6dd25b4..59201d9f3 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -108,6 +108,9 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) #endif odvb->pack_start (*hb3, Gtk::PACK_SHRINK, 4); + destinationPreviewLabel = Gtk::manage (new Gtk::Label ()); + destinationPreviewLabel->set_tooltip_markup(M("QUEUE_DESTPREVIEW_TOOLTIP")); + odvb->pack_start (*destinationPreviewLabel); Gtk::RadioButton::Group g = useTemplate->get_group(); useFolder->set_group (g); fdir->add (*odvb); @@ -122,6 +125,7 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) outdirTemplate->set_text (options.savePathTemplate); useTemplate->set_active (options.saveUsePathTemplate); useFolder->set_active (!options.saveUsePathTemplate); + destinationPreviewLabel->set_text (M("QUEUE_DESTPREVIEW_TITLE")); // setup signal handlers outdirTemplate->signal_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); @@ -329,6 +333,7 @@ void BatchQueuePanel::saveOptions () options.savePathTemplate = outdirTemplate->get_text(); options.saveUsePathTemplate = useTemplate->get_active(); options.procQueueEnabled = qAutoStart->get_active(); + batchQueue->updateDestinationPathPreview(); } bool BatchQueuePanel::handleShortcutKey (GdkEventKey* event) @@ -358,6 +363,11 @@ bool BatchQueuePanel::canStartNext () return queueShouldRun; } +void BatchQueuePanel::setDestinationPreviewText(const Glib::ustring &destinationPath) +{ + destinationPreviewLabel->set_text(destinationPath); +} + void BatchQueuePanel::pathFolderButtonPressed () { @@ -381,6 +391,7 @@ void BatchQueuePanel::pathFolderButtonPressed () void BatchQueuePanel::pathFolderChanged () { options.savePathFolder = outdirFolder->get_filename(); + batchQueue->updateDestinationPathPreview(); } void BatchQueuePanel::formatChanged(const Glib::ustring& format) diff --git a/rtgui/batchqueuepanel.h b/rtgui/batchqueuepanel.h index db4e243e9..d73f8b893 100644 --- a/rtgui/batchqueuepanel.h +++ b/rtgui/batchqueuepanel.h @@ -42,6 +42,7 @@ class BatchQueuePanel : public Gtk::Box, Gtk::CheckButton* qAutoStart; Gtk::Entry* outdirTemplate; + Gtk::Label* destinationPreviewLabel; MyFileChooserButton* outdirFolder; Gtk::Button* outdirFolderButton; Gtk::RadioButton* useTemplate; @@ -72,6 +73,7 @@ public: // batchqueuelistener interface void queueSizeChanged(int qsize, bool queueRunning, bool queueError, const Glib::ustring& queueErrorMessage) override; bool canStartNext() override; + void setDestinationPreviewText(const Glib::ustring& destinationPath) override; private: void startBatchProc (); From 587e0c67829259c68fac020ffc3b43fba965a836 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sat, 6 Jan 2024 16:32:14 -0500 Subject: [PATCH 02/19] Simplified BatchQueue::updateDestinationPathPreview after noticing that calcAutoFileNameBase handles all cases --- rtgui/batchqueue.cc | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 8d2ad176e..27b4400e1 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -575,24 +575,7 @@ void BatchQueue::updateDestinationPathPreview() { auto &entry = *selected.at(0); int sequence = 0; // Sequence during subsequent queue processing can't be determined here - Glib::ustring baseDestination; - if (options.saveUsePathTemplate) - { - baseDestination = calcAutoFileNameBase(entry.filename, sequence); - } - else - { - Glib::ustring baseFilename; - int extpos = entry.filename.size() - 1; - for (; extpos >= 0 && entry.filename[extpos] != '.'; extpos--) - { - } - for (int k = extpos - 1; k >= 0 && entry.filename[k] != '/' && entry.filename[k] != '\\'; k--) - { - baseFilename = entry.filename[k] + baseFilename; - } - baseDestination = options.savePathFolder + '/' + baseFilename; - } + Glib::ustring baseDestination = calcAutoFileNameBase(entry.filename, sequence); Glib::ustring destination = Glib::ustring::compose ("%1.%2", baseDestination, options.saveFormatBatch.format); if (listener) From b8d3f90ca041779cbd8052ba25ba926ab32114a6 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sat, 6 Jan 2024 18:01:56 -0500 Subject: [PATCH 03/19] Reimplement template %dN specifier, making %d-N count from start of path, not end Also made %pN selectively skip the next character only if it's a slash or backslash, so for example %p2/a, %p2\a and %p2a produce the same result. --- rtgui/batchqueue.cc | 62 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 27b4400e1..732580599 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -824,6 +824,47 @@ rtengine::ProcessingJob* BatchQueue::imageReady(rtengine::IImagefloat* img) return processing ? processing->job : nullptr; } +// Combine a range of elements from "names" into a slash-delimited path +static inline Glib::ustring combineDirectoryNames(unsigned startIndex, unsigned endIndex, const std::vector & names) +{ + Glib::ustring resultPath; + for (unsigned i = startIndex; i <= endIndex && i < names.size(); ++i) + { + resultPath = resultPath + names[i] + '/'; + } + return resultPath; +} + +// Look for N or -N in templateText at position ix, meaning "index from end" and "index from start" +// For N, return Nth index from the end, and for -N return the Nth index from the start +static inline unsigned decodePathIndex(unsigned & ix, Glib::ustring & templateText, size_t numPathElements) +{ + unsigned pathIndex = numPathElements; // means input was invalid + bool fromStart = false; + if (ix < templateText.size()) + { + if (templateText[ix] == '-') + { + fromStart = true; // minus sign means N is from the start rather than the end of the path + ix++; + } + } + if (ix < templateText.size()) + { + unsigned n = templateText[ix] - '1'; + if (!fromStart) + { + // n=1 is the last element, n=2 is the one before that + n = numPathElements - n - 1; + } + if (n < numPathElements) + { + pathIndex = n; + } + } + return pathIndex; +} + // Calculates automatic filename of processed batch entry, but just the base name // example output: "c:\out\converted\dsc0121" Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileName, int sequence) @@ -847,7 +888,9 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam tok = tok + origFileName[i++]; } - da.push_back (tok); + if (i < origFileName.size()) { // omit the last token, which is the file name + da.push_back (tok); + } } if (origFileName[0] == '/') { @@ -898,19 +941,24 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam if (options.savePathTemplate[ix] == 'p') { ix++; - unsigned int i = options.savePathTemplate[ix] - '0'; + unsigned int i = options.savePathTemplate[ix] - '1'; if (i < pa.size()) { path = path + pa[pa.size() - i - 1] + '/'; } - + // If the next template character is a slash or backslash, skip it, because path already has a trailing slash ix++; + if (ix < options.savePathTemplate.size() && options.savePathTemplate[ix] != '/' && options.savePathTemplate[ix] != '\\') { + ix--; + } } else if (options.savePathTemplate[ix] == 'd') { + // insert a single directory name from the file's path + // da.size()-1 omits the last element, which is the filename ix++; - unsigned i = options.savePathTemplate[ix] - '0'; - - if (i < da.size()) { - path = path + da[da.size() - i - 1]; + unsigned n = decodePathIndex(ix, options.savePathTemplate, da.size()); + if (n < da.size()) + { + path += da[n]; } } else if (options.savePathTemplate[ix] == 'f') { path = path + filename; From 21c53823ee766c90d57a0e7d1b3b8882d0ffb4db Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sat, 6 Jan 2024 18:21:59 -0500 Subject: [PATCH 04/19] Reimplemented %p template specifier to use new method, added %P specifier The %P specifier includes directories from the start of the file path, whereas the original %p specifier includes them from the end. In both cases N is from the last directory in the path, and -N is from the first directory in the path (N=1..9). --- rtgui/batchqueue.cc | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 732580599..cb9127333 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -837,6 +837,7 @@ static inline Glib::ustring combineDirectoryNames(unsigned startIndex, unsigned // Look for N or -N in templateText at position ix, meaning "index from end" and "index from start" // For N, return Nth index from the end, and for -N return the Nth index from the start +// N is a digit 1 through 9 static inline unsigned decodePathIndex(unsigned & ix, Glib::ustring & templateText, size_t numPathElements) { unsigned pathIndex = numPathElements; // means input was invalid @@ -854,7 +855,6 @@ static inline unsigned decodePathIndex(unsigned & ix, Glib::ustring & templateTe unsigned n = templateText[ix] - '1'; if (!fromStart) { - // n=1 is the last element, n=2 is the one before that n = numPathElements - n - 1; } if (n < numPathElements) @@ -870,7 +870,6 @@ static inline unsigned decodePathIndex(unsigned & ix, Glib::ustring & templateTe Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileName, int sequence) { - std::vector pa; std::vector da; for (size_t i = 0; i < origFileName.size(); i++) { @@ -893,26 +892,8 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam } } - if (origFileName[0] == '/') { - pa.push_back ("/" + da[0]); - } else if (origFileName[0] == '\\') { - if (origFileName.size() > 1 && origFileName[1] == '\\') { - pa.push_back ("\\\\" + da[0]); - } else { - pa.push_back ("/" + da[0]); - } - } else { - pa.push_back (da[0]); - } - - for (size_t i = 1; i < da.size(); i++) { - pa.push_back (pa[i - 1] + "/" + da[i]); - } - // for (int i=0; i Date: Sun, 7 Jan 2024 10:09:45 -0500 Subject: [PATCH 05/19] Update destination preview whenever the save format changes. --- rtgui/batchqueuepanel.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 59201d9f3..fb6e37c46 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -397,4 +397,5 @@ void BatchQueuePanel::pathFolderChanged () void BatchQueuePanel::formatChanged(const Glib::ustring& format) { options.saveFormatBatch = saveFormatPanel->getFormat(); + batchQueue->updateDestinationPathPreview(); } From 5accf1e9dbe381de17942e3b7c1fc006ab560e58 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 7 Jan 2024 10:31:05 -0500 Subject: [PATCH 06/19] Add myself to the list of authors --- AUTHORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 374a7935b..3afd09dc2 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -20,6 +20,7 @@ Development contributors, in last name alphabetical order: Rüdiger Franke Jean-Christophe Frisch Ilias Giarimis + Scott Gilbertson Alberto Griggio Steve Herrell Philippe Hupé From d9511d9af8b55e6771bc2665132a3b196013e4e4 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 7 Jan 2024 10:42:44 -0500 Subject: [PATCH 07/19] Update QUEUE_LOCATION_TEMPLATE_TOOLTIP text to describe new specifiers Describe %dN, %d-N, %pN, %p-N, %PN, %P-N and %f specifiers Add examples using the new P specifier and -N terms --- rtdata/languages/default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 2f22b4642..3af6b108c 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2106,7 +2106,7 @@ QUEUE_DESTPREVIEW_TOOLTIP;Destination path for the first selected image appears QUEUE_FORMAT_TITLE;File Format QUEUE_LOCATION_FOLDER;Save to folder QUEUE_LOCATION_TEMPLATE;Use template -QUEUE_LOCATION_TEMPLATE_TOOLTIP;Specify the output location based on the source photo's location, rank, trash status or position in the queue.\n\nUsing the following pathname as an example:\n/home/tom/photos/2010-10-31/photo1.raw\nthe meaning of the formatting strings follows:\n%d4 = home\n%d3 = tom\n%d2 = photos\n%d1 = 2010-10-31\n%f = photo1\n%p1 = /home/tom/photos/2010-10-31/\n%p2 = /home/tom/photos/\n%p3 = /home/tom/\n%p4 = /home/\n\n%r will be replaced by the photo's rank. If the photo is unranked, '0' is used. If the photo is in the trash, 'x' is used.\n\n%s1, ..., %s9 will be replaced by the photo's initial position in the queue at the time the queue is started. The number specifies the padding, e.g. %s3 results in '001'.\n\nIf you want to save the output image alongside the source image, write:\n%p1/%f\n\nIf you want to save the output image in a folder named 'converted' located in the source photo's folder, write:\n%p1/converted/%f\n\nIf you want to save the output image in\n'/home/tom/photos/converted/2010-10-31', write:\n%p2/converted/%d1/%f +QUEUE_LOCATION_TEMPLATE_TOOLTIP;Specify the output location based on the source photo's location, rank, trash status or position in the queue.\n\n%dN, %d-N, %pN, %p-N, %PN and %P-N (N = 1..9) will be replaced by elements of the image file's directory path (not including the file name):\n%dN = Nth directory from the end of the path\n%d-N = Nth directory from the start of the path\n%pN = all directories up to the Nth from the end of the path\n%p-N = the first N directories in the path\n%PN = the last N directories in the path\n%P-N = all directories from the Nth to the end of the path\n%f will be replaced with the base name of the file, without the extension removed.\nFor Windows paths, %d-1 is the drive letter and colon, and %d-2 is the base directory on that drive.\n\nUsing the following pathname as an example:\n/home/tom/photos/2010-10-31/photo1.raw\nthe meaning of the formatting strings follows:\n%d4 = %d-1 = home\n%d3 = %d-2 = tom\n%d2 = %d-3 = photos\n%d1 = %d-4 = 2010-10-31\n%p1 = %p-4 = /home/tom/photos/2010-10-31/\n%p2 = %p-3 = /home/tom/photos/\n%p3 = %p-2 = /home/tom/\n%p4 = %p-1 = /home/\n%P1 = %P-4 = 2010-10-31/\n%P2 = %P-3 = photos/2010-10-31/\n%P3 = %P-2 = tom/photos/2010-10-31/\n%P4 = %P-1 = /home/tom/photos/2010-10-31/\n%f = photo1\n\n%r will be replaced by the photo's rank. If the photo is unranked, '0' is used. If the photo is in the trash, 'x' is used.\n\n%s1, ..., %s9 will be replaced by the photo's initial position in the queue at the time the queue is started. The number specifies the padding, e.g. %s3 results in '001'.\n\nIf you want to save the output image alongside the source image, write:\n%p1/%f\n\nIf you want to save the output image in a folder named 'converted' located in the source photo's folder, write:\n%p1/converted/%f\n\nIf you want to save the output image in\n'/home/tom/photos/converted/2010-10-31', write:\n%p-3/converted/%P-4/%f QUEUE_LOCATION_TITLE;Output Location QUEUE_STARTSTOP_TOOLTIP;Start or stop processing the images in the queue.\n\nShortcut: Ctrl+s SAMPLEFORMAT_0;Unknown data format From f92e07e5cf904757e19f9da61f44aa19b0c4e5eb Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 7 Jan 2024 10:52:01 -0500 Subject: [PATCH 08/19] Make destination path preview label selectable, so its contents can be copied to the clipboard --- rtgui/batchqueuepanel.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index fb6e37c46..3fd52df93 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -110,6 +110,7 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) odvb->pack_start (*hb3, Gtk::PACK_SHRINK, 4); destinationPreviewLabel = Gtk::manage (new Gtk::Label ()); destinationPreviewLabel->set_tooltip_markup(M("QUEUE_DESTPREVIEW_TOOLTIP")); + destinationPreviewLabel->set_selectable(true); // so users can copy the path to the clipboard odvb->pack_start (*destinationPreviewLabel); Gtk::RadioButton::Group g = useTemplate->get_group(); useFolder->set_group (g); From 6df930b639a833354772747f43ac3e46d14e8b30 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 7 Jan 2024 11:09:24 -0500 Subject: [PATCH 09/19] Minor tooltip change: shorter explanation of %f location template specifier --- rtdata/languages/default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 3af6b108c..bf43596dc 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2106,7 +2106,7 @@ QUEUE_DESTPREVIEW_TOOLTIP;Destination path for the first selected image appears QUEUE_FORMAT_TITLE;File Format QUEUE_LOCATION_FOLDER;Save to folder QUEUE_LOCATION_TEMPLATE;Use template -QUEUE_LOCATION_TEMPLATE_TOOLTIP;Specify the output location based on the source photo's location, rank, trash status or position in the queue.\n\n%dN, %d-N, %pN, %p-N, %PN and %P-N (N = 1..9) will be replaced by elements of the image file's directory path (not including the file name):\n%dN = Nth directory from the end of the path\n%d-N = Nth directory from the start of the path\n%pN = all directories up to the Nth from the end of the path\n%p-N = the first N directories in the path\n%PN = the last N directories in the path\n%P-N = all directories from the Nth to the end of the path\n%f will be replaced with the base name of the file, without the extension removed.\nFor Windows paths, %d-1 is the drive letter and colon, and %d-2 is the base directory on that drive.\n\nUsing the following pathname as an example:\n/home/tom/photos/2010-10-31/photo1.raw\nthe meaning of the formatting strings follows:\n%d4 = %d-1 = home\n%d3 = %d-2 = tom\n%d2 = %d-3 = photos\n%d1 = %d-4 = 2010-10-31\n%p1 = %p-4 = /home/tom/photos/2010-10-31/\n%p2 = %p-3 = /home/tom/photos/\n%p3 = %p-2 = /home/tom/\n%p4 = %p-1 = /home/\n%P1 = %P-4 = 2010-10-31/\n%P2 = %P-3 = photos/2010-10-31/\n%P3 = %P-2 = tom/photos/2010-10-31/\n%P4 = %P-1 = /home/tom/photos/2010-10-31/\n%f = photo1\n\n%r will be replaced by the photo's rank. If the photo is unranked, '0' is used. If the photo is in the trash, 'x' is used.\n\n%s1, ..., %s9 will be replaced by the photo's initial position in the queue at the time the queue is started. The number specifies the padding, e.g. %s3 results in '001'.\n\nIf you want to save the output image alongside the source image, write:\n%p1/%f\n\nIf you want to save the output image in a folder named 'converted' located in the source photo's folder, write:\n%p1/converted/%f\n\nIf you want to save the output image in\n'/home/tom/photos/converted/2010-10-31', write:\n%p-3/converted/%P-4/%f +QUEUE_LOCATION_TEMPLATE_TOOLTIP;Specify the output location based on the source photo's location, rank, trash status or position in the queue.\n\n%dN, %d-N, %pN, %p-N, %PN and %P-N (N = 1..9) will be replaced by elements of the image file's directory path (not including the file name):\n%dN = Nth directory from the end of the path\n%d-N = Nth directory from the start of the path\n%pN = all directories up to the Nth from the end of the path\n%p-N = the first N directories in the path\n%PN = the last N directories in the path\n%P-N = all directories from the Nth to the end of the path\n%f = base filename (no extension)\nFor Windows paths, %d-1 is the drive letter and colon, and %d-2 is the base directory on that drive.\n\nUsing the following pathname as an example:\n/home/tom/photos/2010-10-31/photo1.raw\nthe meaning of the formatting strings follows:\n%d4 = %d-1 = home\n%d3 = %d-2 = tom\n%d2 = %d-3 = photos\n%d1 = %d-4 = 2010-10-31\n%p1 = %p-4 = /home/tom/photos/2010-10-31/\n%p2 = %p-3 = /home/tom/photos/\n%p3 = %p-2 = /home/tom/\n%p4 = %p-1 = /home/\n%P1 = %P-4 = 2010-10-31/\n%P2 = %P-3 = photos/2010-10-31/\n%P3 = %P-2 = tom/photos/2010-10-31/\n%P4 = %P-1 = /home/tom/photos/2010-10-31/\n%f = photo1\n\n%r will be replaced by the photo's rank. If the photo is unranked, '0' is used. If the photo is in the trash, 'x' is used.\n\n%s1, ..., %s9 will be replaced by the photo's initial position in the queue at the time the queue is started. The number specifies the padding, e.g. %s3 results in '001'.\n\nIf you want to save the output image alongside the source image, write:\n%p1/%f\n\nIf you want to save the output image in a folder named 'converted' located in the source photo's folder, write:\n%p1/converted/%f\n\nIf you want to save the output image in\n'/home/tom/photos/converted/2010-10-31', write:\n%p-3/converted/%P-4/%f QUEUE_LOCATION_TITLE;Output Location QUEUE_STARTSTOP_TOOLTIP;Start or stop processing the images in the queue.\n\nShortcut: Ctrl+s SAMPLEFORMAT_0;Unknown data format From df4102846831f67aa960d7ff74346014f92be85b Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 7 Jan 2024 11:10:05 -0500 Subject: [PATCH 10/19] On Windows, use backslashes in template-generated paths (but continue to accept either / or \ in input strings, on any platform) Also deleted an unused helper function. --- rtgui/batchqueue.cc | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index cb9127333..61f1c082d 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -43,6 +43,12 @@ using namespace std; using namespace rtengine; +#ifdef _WIN32 +#define PATH_SEPARATOR '\\'; +#else +#define PATH_SEPARATOR '/'; +#endif + BatchQueue::BatchQueue (FileCatalog* aFileCatalog) : processing(nullptr), fileCatalog(aFileCatalog), sequence(0), listener(nullptr) { @@ -824,17 +830,6 @@ rtengine::ProcessingJob* BatchQueue::imageReady(rtengine::IImagefloat* img) return processing ? processing->job : nullptr; } -// Combine a range of elements from "names" into a slash-delimited path -static inline Glib::ustring combineDirectoryNames(unsigned startIndex, unsigned endIndex, const std::vector & names) -{ - Glib::ustring resultPath; - for (unsigned i = startIndex; i <= endIndex && i < names.size(); ++i) - { - resultPath = resultPath + names[i] + '/'; - } - return resultPath; -} - // Look for N or -N in templateText at position ix, meaning "index from end" and "index from start" // For N, return Nth index from the end, and for -N return the Nth index from the start // N is a digit 1 through 9 @@ -926,7 +921,7 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam unsigned n = decodePathIndex(ix, options.savePathTemplate, da.size()); if (n < da.size()) { for (unsigned i=n; i Date: Sun, 7 Jan 2024 11:14:52 -0500 Subject: [PATCH 11/19] Minor comment clarification --- rtgui/batchqueue.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 61f1c082d..bdf6c6e5e 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -924,7 +924,7 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam path = path + da[i] + PATH_SEPARATOR; } } - // If the next template character is a slash or backslash, skip it, because path already has a trailing slash + // If the next template character is a separator, skip it, because path already has one ix++; if (ix < options.savePathTemplate.size() && options.savePathTemplate[ix] != '/' && options.savePathTemplate[ix] != '\\') { ix--; @@ -936,7 +936,7 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam for (unsigned i=0; i<=n && i Date: Sun, 7 Jan 2024 11:49:19 -0500 Subject: [PATCH 12/19] Reversed %p and %P processing cases for location templates, which were opposite to what the help says. --- rtgui/batchqueue.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index bdf6c6e5e..c3723515f 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -915,7 +915,7 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam if (options.savePathTemplate[ix] == '%') { ix++; - if (options.savePathTemplate[ix] == 'p') { + if (options.savePathTemplate[ix] == 'P') { // insert path elements from given index to the end ix++; unsigned n = decodePathIndex(ix, options.savePathTemplate, da.size()); @@ -929,7 +929,7 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam if (ix < options.savePathTemplate.size() && options.savePathTemplate[ix] != '/' && options.savePathTemplate[ix] != '\\') { ix--; } - } else if (options.savePathTemplate[ix] == 'P') { + } else if (options.savePathTemplate[ix] == 'p') { // insert path elements from the start of the path up to the given index ix++; unsigned n = decodePathIndex(ix, options.savePathTemplate, da.size()); From 9e310b7454a604ae298ef11d05806809129a9b87 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Wed, 10 Jan 2024 18:47:14 -0500 Subject: [PATCH 13/19] Minor changes per feedback in issue #6915 (mostly code formatting) --- rtgui/batchqueue.cc | 87 +++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index c3723515f..349cefddf 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -49,6 +49,34 @@ using namespace rtengine; #define PATH_SEPARATOR '/'; #endif +namespace // local helper functions +{ + // Look for N or -N in templateText at position ix, meaning "index from end" and "index from start" + // For N, return Nth index from the end, and for -N return the Nth index from the start + // N is a digit 1 through 9 + unsigned int decodePathIndex(unsigned int & ix, Glib::ustring & templateText, size_t numPathElements) + { + unsigned int pathIndex = numPathElements; // means input was invalid + bool fromStart = false; + if (ix < templateText.size()) { + if (templateText[ix] == '-') { + fromStart = true; // minus sign means N is from the start rather than the end of the path + ix++; + } + } + if (ix < templateText.size()) { + unsigned int n = templateText[ix] - '1'; + if (!fromStart) { + n = numPathElements - n - 1; + } + if (n < numPathElements) { + pathIndex = n; + } + } + return pathIndex; + } +} + BatchQueue::BatchQueue (FileCatalog* aFileCatalog) : processing(nullptr), fileCatalog(aFileCatalog), sequence(0), listener(nullptr) { @@ -567,7 +595,7 @@ void BatchQueue::openLastSelectedItemInEditor() { MYREADERLOCK(l, entryRW); - if (selected.size() > 0) { + if (!selected.empty()) { openItemInEditor(selected.back()); } } @@ -577,15 +605,13 @@ void BatchQueue::updateDestinationPathPreview() { MYWRITERLOCK(l, entryRW); - if (selected.size()) - { + if (!selected.empty()) { auto &entry = *selected.at(0); int sequence = 0; // Sequence during subsequent queue processing can't be determined here Glib::ustring baseDestination = calcAutoFileNameBase(entry.filename, sequence); Glib::ustring destination = Glib::ustring::compose ("%1.%2", baseDestination, options.saveFormatBatch.format); - if (listener) - { + if (listener) { listener->setDestinationPreviewText(destination); } } @@ -830,36 +856,6 @@ rtengine::ProcessingJob* BatchQueue::imageReady(rtengine::IImagefloat* img) return processing ? processing->job : nullptr; } -// Look for N or -N in templateText at position ix, meaning "index from end" and "index from start" -// For N, return Nth index from the end, and for -N return the Nth index from the start -// N is a digit 1 through 9 -static inline unsigned decodePathIndex(unsigned & ix, Glib::ustring & templateText, size_t numPathElements) -{ - unsigned pathIndex = numPathElements; // means input was invalid - bool fromStart = false; - if (ix < templateText.size()) - { - if (templateText[ix] == '-') - { - fromStart = true; // minus sign means N is from the start rather than the end of the path - ix++; - } - } - if (ix < templateText.size()) - { - unsigned n = templateText[ix] - '1'; - if (!fromStart) - { - n = numPathElements - n - 1; - } - if (n < numPathElements) - { - pathIndex = n; - } - } - return pathIndex; -} - // Calculates automatic filename of processed batch entry, but just the base name // example output: "c:\out\converted\dsc0121" Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileName, int sequence) @@ -918,10 +914,10 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam if (options.savePathTemplate[ix] == 'P') { // insert path elements from given index to the end ix++; - unsigned n = decodePathIndex(ix, options.savePathTemplate, da.size()); + unsigned int n = decodePathIndex(ix, options.savePathTemplate, da.size()); if (n < da.size()) { - for (unsigned i=n; i Date: Wed, 10 Jan 2024 18:55:52 -0500 Subject: [PATCH 14/19] Code formatting: move ampersands next to types --- rtgui/batchqueue.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 349cefddf..df653976c 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -54,7 +54,7 @@ namespace // local helper functions // Look for N or -N in templateText at position ix, meaning "index from end" and "index from start" // For N, return Nth index from the end, and for -N return the Nth index from the start // N is a digit 1 through 9 - unsigned int decodePathIndex(unsigned int & ix, Glib::ustring & templateText, size_t numPathElements) + unsigned int decodePathIndex(unsigned int& ix, Glib::ustring& templateText, size_t numPathElements) { unsigned int pathIndex = numPathElements; // means input was invalid bool fromStart = false; @@ -606,7 +606,7 @@ void BatchQueue::updateDestinationPathPreview() MYWRITERLOCK(l, entryRW); if (!selected.empty()) { - auto &entry = *selected.at(0); + auto& entry = *selected.at(0); int sequence = 0; // Sequence during subsequent queue processing can't be determined here Glib::ustring baseDestination = calcAutoFileNameBase(entry.filename, sequence); Glib::ustring destination = Glib::ustring::compose ("%1.%2", baseDestination, options.saveFormatBatch.format); From 343b5ecc683d4a5f7ed71bf99e6800b8d1d470d8 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Mon, 15 Jan 2024 14:40:56 -0500 Subject: [PATCH 15/19] Left-justify the queue destination preview label and allow it to scroll horizontally --- rtgui/batchqueuepanel.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 3fd52df93..e35149326 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -109,9 +109,13 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) odvb->pack_start (*hb3, Gtk::PACK_SHRINK, 4); destinationPreviewLabel = Gtk::manage (new Gtk::Label ()); - destinationPreviewLabel->set_tooltip_markup(M("QUEUE_DESTPREVIEW_TOOLTIP")); - destinationPreviewLabel->set_selectable(true); // so users can copy the path to the clipboard - odvb->pack_start (*destinationPreviewLabel); + destinationPreviewLabel->set_tooltip_markup (M("QUEUE_DESTPREVIEW_TOOLTIP")); + destinationPreviewLabel->set_selectable (true); // so users can copy the path to the clipboard + destinationPreviewLabel->set_halign (Gtk::ALIGN_START); + auto destinationPreviewScrolledWindow = Gtk::manage(new Gtk::ScrolledWindow ()); + destinationPreviewScrolledWindow->set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + destinationPreviewScrolledWindow->add (*destinationPreviewLabel); + odvb->pack_start (*destinationPreviewScrolledWindow, Gtk::PACK_SHRINK); Gtk::RadioButton::Group g = useTemplate->get_group(); useFolder->set_group (g); fdir->add (*odvb); From a39e6779e4cee8b92ff035a9cd21fbb3d2843657 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Mon, 15 Jan 2024 15:27:09 -0500 Subject: [PATCH 16/19] Fix: If %p or %P queue template term includes start of file path, prepend the leading /, \ or \\ from the file path --- rtgui/batchqueue.cc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index df653976c..bb2d7526f 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -75,6 +75,23 @@ namespace // local helper functions } return pathIndex; } + + // Extract the initial characters from a canonical absolute path, and append + // those to a path string. Initial characters are '/' for Unix/Linux paths and + // '\\' for UNC paths. A single backslash is also accepted, for driveless + // Windows paths. + void appendAbsolutePathPrefix(Glib::ustring& path, const Glib::ustring& absolutePath) + { + if (absolutePath[0] == '/') { + path += '/'; // Start of a Unix/Linux path + } else if (absolutePath[0] == '\\') { + if (absolutePath.size() > 1 && absolutePath[1] == '\\') { + path += "\\\\"; // Start of a UNC path + } else { + path += '\\'; // Start of a Windows path that does not include a drive letter + } + } + } } BatchQueue::BatchQueue (FileCatalog* aFileCatalog) : processing(nullptr), fileCatalog(aFileCatalog), sequence(0), listener(nullptr) @@ -916,6 +933,9 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam ix++; unsigned int n = decodePathIndex(ix, options.savePathTemplate, da.size()); if (n < da.size()) { + if (n == 0) { + appendAbsolutePathPrefix(path, origFileName); + } for (unsigned int i=n; i < da.size(); i++) { path += da[i] + PATH_SEPARATOR; } @@ -930,6 +950,9 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam ix++; unsigned int n = decodePathIndex(ix, options.savePathTemplate, da.size()); for (unsigned int i=0; i <= n && i < da.size(); i++) { + if (i == 0) { + appendAbsolutePathPrefix(path, origFileName); + } path += da[i] + PATH_SEPARATOR; } // If the next template character is a separator, skip it, because path already has one From 1df9b4869e379f8f937831c6487b88c7208f015e Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Mon, 15 Jan 2024 16:39:38 -0500 Subject: [PATCH 17/19] Make %p and %P queue output template specifiers limit invalid range rather than treating that as an error. For example in a 4-element path "first 5 elements" and "last 5 elements" now return all four elements. --- rtgui/batchqueue.cc | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index bb2d7526f..53d31d76b 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -51,12 +51,13 @@ using namespace rtengine; namespace // local helper functions { - // Look for N or -N in templateText at position ix, meaning "index from end" and "index from start" - // For N, return Nth index from the end, and for -N return the Nth index from the start - // N is a digit 1 through 9 - unsigned int decodePathIndex(unsigned int& ix, Glib::ustring& templateText, size_t numPathElements) + // Look for N or -N in templateText at position ix, meaning "index from end" and "index from start". + // For N, return Nth index from the end, and for -N return the Nth index from the start. + // N is a digit 1 through 9. The returned value is not range-checked, so it may be >=numPathElements. + // or negative. The caller performs any required range-checking. + int decodePathIndex(unsigned int& ix, Glib::ustring& templateText, size_t numPathElements) { - unsigned int pathIndex = numPathElements; // means input was invalid + int pathIndex = (int)numPathElements; // a value that means input was invalid bool fromStart = false; if (ix < templateText.size()) { if (templateText[ix] == '-') { @@ -65,12 +66,9 @@ namespace // local helper functions } } if (ix < templateText.size()) { - unsigned int n = templateText[ix] - '1'; + pathIndex = templateText[ix] - '1'; if (!fromStart) { - n = numPathElements - n - 1; - } - if (n < numPathElements) { - pathIndex = n; + pathIndex = numPathElements - pathIndex - 1; } } return pathIndex; @@ -900,8 +898,8 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam } } -// for (int i=0; i 0) { + appendAbsolutePathPrefix(path, origFileName); + } + for (unsigned int i=0; (int)i <= n && i < da.size(); i++) { path += da[i] + PATH_SEPARATOR; } // If the next template character is a separator, skip it, because path already has one @@ -962,10 +963,9 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam } } else if (options.savePathTemplate[ix] == 'd') { // insert a single directory name from the file's path - // da.size()-1 omits the last element, which is the filename ix++; unsigned int n = decodePathIndex(ix, options.savePathTemplate, da.size()); - if (n < da.size()) { + if (n >= 0 && n < da.size()) { path += da[n]; } } else if (options.savePathTemplate[ix] == 'f') { From 6cbc448f63f16bf660d590306b666ecac0d3d85c Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Mon, 15 Jan 2024 17:13:40 -0500 Subject: [PATCH 18/19] Handle Samba-style UNC prefix '//' in %p and %P queue output template specifiers --- rtgui/batchqueue.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 53d31d76b..e7de30d30 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -76,12 +76,16 @@ namespace // local helper functions // Extract the initial characters from a canonical absolute path, and append // those to a path string. Initial characters are '/' for Unix/Linux paths and - // '\\' for UNC paths. A single backslash is also accepted, for driveless + // '\\' or '//' for UNC paths. A single backslash is also accepted, for driveless // Windows paths. void appendAbsolutePathPrefix(Glib::ustring& path, const Glib::ustring& absolutePath) { if (absolutePath[0] == '/') { - path += '/'; // Start of a Unix/Linux path + if (absolutePath.size() > 1 && absolutePath[1] == '/') { + path += "//"; // Start of a Samba UNC path + } else { + path += '/'; // Start of a Unix/Linux path + } } else if (absolutePath[0] == '\\') { if (absolutePath.size() > 1 && absolutePath[1] == '\\') { path += "\\\\"; // Start of a UNC path From 11a0a0b6975a62aa28d6623770b60f9dbcbd7063 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Tue, 16 Jan 2024 07:54:12 -0500 Subject: [PATCH 19/19] Fixes per pull request comments: fix %p-1 missing slash, use static_cast, fix int/unsigned mismatches --- rtgui/batchqueue.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index e7de30d30..2811e3445 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -57,7 +57,7 @@ namespace // local helper functions // or negative. The caller performs any required range-checking. int decodePathIndex(unsigned int& ix, Glib::ustring& templateText, size_t numPathElements) { - int pathIndex = (int)numPathElements; // a value that means input was invalid + int pathIndex = static_cast(numPathElements); // a value that means input was invalid bool fromStart = false; if (ix < templateText.size()) { if (templateText[ix] == '-') { @@ -447,7 +447,7 @@ Glib::ustring BatchQueue::getTempFilenameForParams( const Glib::ustring &filenam timeval tv; gettimeofday(&tv, nullptr); char mseconds[11]; - snprintf(mseconds, sizeof(mseconds), "%d", (int)(tv.tv_usec / 1000)); + snprintf(mseconds, sizeof(mseconds), "%d", static_cast((tv.tv_usec / 1000))); time_t rawtime; struct tm *timeinfo; char stringTimestamp [80]; @@ -937,11 +937,11 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam if (n < 0) { n = 0; // if too many elements specified, return all available elements } - if (n < (int)da.size()) { + if (n < static_cast(da.size())) { if (n == 0) { appendAbsolutePathPrefix(path, origFileName); } - for (unsigned int i = (unsigned int)n; i < da.size(); i++) { + for (unsigned int i = static_cast(n); i < da.size(); i++) { path += da[i] + PATH_SEPARATOR; } } @@ -954,10 +954,10 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam // insert path elements from the start of the path up to the given index ix++; int n = decodePathIndex(ix, options.savePathTemplate, da.size()); - if (n > 0) { + if (n >= 0) { appendAbsolutePathPrefix(path, origFileName); } - for (unsigned int i=0; (int)i <= n && i < da.size(); i++) { + for (unsigned int i=0; static_cast(i) <= n && i < da.size(); i++) { path += da[i] + PATH_SEPARATOR; } // If the next template character is a separator, skip it, because path already has one @@ -968,8 +968,8 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam } else if (options.savePathTemplate[ix] == 'd') { // insert a single directory name from the file's path ix++; - unsigned int n = decodePathIndex(ix, options.savePathTemplate, da.size()); - if (n >= 0 && n < da.size()) { + int n = decodePathIndex(ix, options.savePathTemplate, da.size()); + if (n >= 0 && n < static_cast(da.size())) { path += da[n]; } } else if (options.savePathTemplate[ix] == 'f') {