From bfcfaca0ba0b392ad76144f8a5adb78c1a35d1f4 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sat, 3 Feb 2024 13:02:02 -0500 Subject: [PATCH 01/22] First try at adding expandable queue template help, using a Gtx::Paned. Hiding doesn't work right yet. Click a thumbnail and the text disappears, but the border between widgets doesn't move to the left side. I tried using a Gtk::Expander, but couldn't get it to expand horizontally. --- rtgui/batchqueuepanel.cc | 20 +++++++++++++++++++- rtgui/batchqueuepanel.h | 2 ++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index e35149326..4e03b2a74 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -147,8 +147,25 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) topBox->pack_start (*fdir, Gtk::PACK_EXPAND_WIDGET, 4); topBox->pack_start (*fformat, Gtk::PACK_EXPAND_WIDGET, 4); + // FIXME: THIS IS SO FAR JUST A TEST THING + middleSplitPane = Gtk::manage (new Gtk::Paned(Gtk::ORIENTATION_HORIZONTAL)); + templateHelpTextView = Gtk::manage (new Gtk::TextView()); + templateHelpTextView->set_editable(false); + templateHelpTextView->set_wrap_mode(Gtk::WRAP_WORD); + Gtk::ScrolledWindow* scrolledTemplateHelpWindow = Gtk::manage(new Gtk::ScrolledWindow()); + scrolledTemplateHelpWindow->add(*templateHelpTextView); + { + auto helptext = M("QUEUE_LOCATION_TEMPLATE_TOOLTIP"); + auto buffer = templateHelpTextView->get_buffer(); + buffer->create_tag("bold"); + buffer->create_tag("italic"); + buffer->insert_markup(buffer->begin(), helptext); + } + middleSplitPane->pack1 (*scrolledTemplateHelpWindow); + middleSplitPane->pack2 (*batchQueue); + // add middle browser area - pack_start (*batchQueue); + pack_start (*middleSplitPane); // lower box with thumbnail zoom bottomBox = Gtk::manage (new Gtk::Box ()); @@ -371,6 +388,7 @@ bool BatchQueuePanel::canStartNext () void BatchQueuePanel::setDestinationPreviewText(const Glib::ustring &destinationPath) { destinationPreviewLabel->set_text(destinationPath); + templateHelpTextView->hide(); // FIXME: REMOVE TESTING THING } void BatchQueuePanel::pathFolderButtonPressed () diff --git a/rtgui/batchqueuepanel.h b/rtgui/batchqueuepanel.h index d73f8b893..ce04b2257 100644 --- a/rtgui/batchqueuepanel.h +++ b/rtgui/batchqueuepanel.h @@ -52,8 +52,10 @@ class BatchQueuePanel : public Gtk::Box, RTWindow* parent; BatchQueue* batchQueue; + Gtk::TextView* templateHelpTextView; Gtk::Box* bottomBox; Gtk::Box* topBox; + Gtk::Paned* middleSplitPane; std::atomic queueShouldRun; From 7632d0df7c9f839e7a436b4a0170830d751f5008 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sat, 3 Feb 2024 13:13:25 -0500 Subject: [PATCH 02/22] Got template help show/hide working (I had been hiding the wrong widget) --- rtgui/batchqueuepanel.cc | 9 +++++++-- rtgui/batchqueuepanel.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 4e03b2a74..8dfde876c 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -152,7 +152,7 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) templateHelpTextView = Gtk::manage (new Gtk::TextView()); templateHelpTextView->set_editable(false); templateHelpTextView->set_wrap_mode(Gtk::WRAP_WORD); - Gtk::ScrolledWindow* scrolledTemplateHelpWindow = Gtk::manage(new Gtk::ScrolledWindow()); + scrolledTemplateHelpWindow = Gtk::manage(new Gtk::ScrolledWindow()); scrolledTemplateHelpWindow->add(*templateHelpTextView); { auto helptext = M("QUEUE_LOCATION_TEMPLATE_TOOLTIP"); @@ -388,7 +388,12 @@ bool BatchQueuePanel::canStartNext () void BatchQueuePanel::setDestinationPreviewText(const Glib::ustring &destinationPath) { destinationPreviewLabel->set_text(destinationPath); - templateHelpTextView->hide(); // FIXME: REMOVE TESTING THING + static bool remove_me = false; + remove_me = !remove_me; + if(remove_me) + scrolledTemplateHelpWindow->hide(); // FIXME: REMOVE TESTING THING + else + scrolledTemplateHelpWindow->show(); // FIXME: REMOVE TESTING THING } void BatchQueuePanel::pathFolderButtonPressed () diff --git a/rtgui/batchqueuepanel.h b/rtgui/batchqueuepanel.h index ce04b2257..70cf5d506 100644 --- a/rtgui/batchqueuepanel.h +++ b/rtgui/batchqueuepanel.h @@ -53,6 +53,7 @@ class BatchQueuePanel : public Gtk::Box, RTWindow* parent; BatchQueue* batchQueue; Gtk::TextView* templateHelpTextView; + Gtk::ScrolledWindow* scrolledTemplateHelpWindow; Gtk::Box* bottomBox; Gtk::Box* topBox; Gtk::Paned* middleSplitPane; From e332446627b84daae0287d282a3b0c6102268174 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sat, 3 Feb 2024 15:28:46 -0500 Subject: [PATCH 03/22] Added "?" toggle button to show/hide template help. I haven't figured out how to make it initially hidden. --- rtgui/batchqueuepanel.cc | 18 +++++++++++------- rtgui/batchqueuepanel.h | 2 ++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 8dfde876c..4d150f4f9 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -73,7 +73,10 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) hb2->pack_start (*useTemplate, Gtk::PACK_SHRINK, 4); outdirTemplate = Gtk::manage (new Gtk::Entry ()); hb2->pack_start (*outdirTemplate); - odvb->pack_start (*hb2, Gtk::PACK_SHRINK, 4); + templateHelpButton = Gtk::manage (new Gtk::ToggleButton("?")); + templateHelpButton->set_tooltip_markup (M ("GENERAL_HELP")); // FIXME: Specific tooltip for this button + hb2->pack_start (*templateHelpButton, Gtk::PACK_SHRINK, 0); + odvb->pack_start (*hb2, Gtk::PACK_SHRINK, 0); outdirTemplate->set_tooltip_markup (M("QUEUE_LOCATION_TEMPLATE_TOOLTIP")); useTemplate->set_tooltip_markup (M("QUEUE_LOCATION_TEMPLATE_TOOLTIP")); Gtk::Box* hb3 = Gtk::manage (new Gtk::Box ()); @@ -136,6 +139,7 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) outdirTemplate->signal_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); useTemplate->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); useFolder->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions)); + templateHelpButton->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::templateHelpButtonToggled)); saveFormatPanel->setListener (this); // setup button bar @@ -163,6 +167,7 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) } middleSplitPane->pack1 (*scrolledTemplateHelpWindow); middleSplitPane->pack2 (*batchQueue); + scrolledTemplateHelpWindow->set_visible(false); // initially hidden, templateHelpButton shows it // add middle browser area pack_start (*middleSplitPane); @@ -339,6 +344,11 @@ void BatchQueuePanel::setGuiFromBatchState(bool queueRunning, int qsize) updateTab(qsize); } +void BatchQueuePanel::templateHelpButtonToggled() +{ + scrolledTemplateHelpWindow->set_visible(templateHelpButton->get_active()); +} + void BatchQueuePanel::addBatchQueueJobs(const std::vector& entries, bool head) { batchQueue->addEntries(entries, head); @@ -388,12 +398,6 @@ bool BatchQueuePanel::canStartNext () void BatchQueuePanel::setDestinationPreviewText(const Glib::ustring &destinationPath) { destinationPreviewLabel->set_text(destinationPath); - static bool remove_me = false; - remove_me = !remove_me; - if(remove_me) - scrolledTemplateHelpWindow->hide(); // FIXME: REMOVE TESTING THING - else - scrolledTemplateHelpWindow->show(); // FIXME: REMOVE TESTING THING } void BatchQueuePanel::pathFolderButtonPressed () diff --git a/rtgui/batchqueuepanel.h b/rtgui/batchqueuepanel.h index 70cf5d506..bdd4ef6de 100644 --- a/rtgui/batchqueuepanel.h +++ b/rtgui/batchqueuepanel.h @@ -54,6 +54,7 @@ class BatchQueuePanel : public Gtk::Box, BatchQueue* batchQueue; Gtk::TextView* templateHelpTextView; Gtk::ScrolledWindow* scrolledTemplateHelpWindow; + Gtk::ToggleButton* templateHelpButton; Gtk::Box* bottomBox; Gtk::Box* topBox; Gtk::Paned* middleSplitPane; @@ -83,6 +84,7 @@ private: void stopBatchProc (); void startOrStopBatchProc(); void setGuiFromBatchState(bool queueRunning, int qsize); + void templateHelpButtonToggled(); void pathFolderChanged (); void pathFolderButtonPressed (); From c7500becb851c26a5322731ea4cd3ceb23a6b490 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sat, 3 Feb 2024 19:24:07 -0500 Subject: [PATCH 04/22] Make template help initially hidden --- rtgui/batchqueuepanel.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 4d150f4f9..3797a7a48 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -168,6 +168,7 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) middleSplitPane->pack1 (*scrolledTemplateHelpWindow); middleSplitPane->pack2 (*batchQueue); scrolledTemplateHelpWindow->set_visible(false); // initially hidden, templateHelpButton shows it + scrolledTemplateHelpWindow->set_no_show_all(true); // add middle browser area pack_start (*middleSplitPane); @@ -346,7 +347,10 @@ void BatchQueuePanel::setGuiFromBatchState(bool queueRunning, int qsize) void BatchQueuePanel::templateHelpButtonToggled() { - scrolledTemplateHelpWindow->set_visible(templateHelpButton->get_active()); + bool visible = templateHelpButton->get_active(); + //scrolledTemplateHelpWindow->set_no_show_all(!visible); + scrolledTemplateHelpWindow->set_visible(visible); + templateHelpTextView->set_visible(visible); } void BatchQueuePanel::addBatchQueueJobs(const std::vector& entries, bool head) From 3fb7296cd130c25234d4e97670288d18982a3ea9 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sat, 10 Feb 2024 13:44:12 -0500 Subject: [PATCH 05/22] Create template help Pango markdown programmatically (partial). Do that the first time the text is shown, rather than at startup. --- rtdata/languages/default | 12 +++++++- rtgui/batchqueuepanel.cc | 64 +++++++++++++++++++++++++++++++++++----- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index bf43596dc..b2c1cf890 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2106,7 +2106,17 @@ 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 = 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 +REMOVE_ME_OLD___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_TEMPLATE_TOOLTIP;Specify the output location based on characteristics such as the source photo's location, rank, trash status or position in the queue.\n\nThe output template field value can include specifiers beginning with %, which are replaced by those characteristics in the actual destination path.\n\nPress the ? button for full instructions. +QUEUE_LOCATION_TEMPLATE_HELP_TITLE;Creating an output template +QUEUE_LOCATION_TEMPLATE_HELP_INTRO;The output template field allows you to to dynamically customize the destination folder and filename. When you include certain specifiers, which begin with %, they are replaced by the program when each file is being saved.\n\nThe sections below describe each type of specifier. +QUEUE_LOCATION_TEMPLATE_HELP_PATHS_TITLE;Directories and partial paths +QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO;The %dN, %d-N, %pN, %p-N, %PN and %P-N (N = 1..9) specifiers will be replaced by elements of the image file's directory path.\nThe format specifiers operate as follows:\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. +QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_1;Using this pathname as an example: +QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX;/home/tom/photos/2010-10-31/photo1.raw +QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS;C:\users\tom\photos\2010-10-31\photo1.raw +QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2;The meanings of the formatting strings are: + 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 diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 3797a7a48..439134977 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -23,6 +23,57 @@ #include "soundman.h" #include "rtimage.h" +namespace // helper functions +{ + + // Populate the buffer of a Gtk::TextView with help text for the location template field + void populateTemplateHelpBuffer(Glib::RefPtr buffer) + { + auto pos = buffer->begin(); + auto insertHeading1 = [&pos, buffer](const Glib::ustring& text) { + pos = buffer->insert_markup(pos, Glib::ustring::format("", text, "\n")); + }; + auto insertHeading2 = [&pos, buffer](const Glib::ustring& text) { + pos = buffer->insert_markup(pos, Glib::ustring::format("\n\n", text, "\n")); + }; + insertHeading1(M("QUEUE_LOCATION_TEMPLATE_HELP_TITLE")); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_INTRO")); + insertHeading2(M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_TITLE")); + printf("[[[%s]]]", M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO").c_str()); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO")); + pos = buffer->insert(pos, "\n"); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_1")); +#ifdef _WIN32 + auto exampleString = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS"); +#else + auto exampleString = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX"); +#endif + pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleString, "\n")); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2")); + pos = buffer->insert(pos, "\n"); + /* FIXME: Still to do here: + Generate text like the original below, but use the actual conversion function to create it: + %d4 = %d-1 = home + %d3 = %d-2 = tom + %d2 = %d-3 = photos + %d1 = %d-4 = 2010-10-31 + %p1 = %p-4 = /home/tom/photos/2010-10-31/ + %p2 = %p-3 = /home/tom/photos/ + %p3 = %p-2 = /home/tom/ + %p4 = %p-1 = /home/ + %P1 = %P-4 = 2010-10-31/ + %P2 = %P-3 = photos/2010-10-31/ + %P3 = %P-2 = tom/photos/2010-10-31/ + %P4 = %P-1 = /home/tom/photos/2010-10-31/ + %f = photo1 + Insert sections for the remaining specifiers: + %r = rank + %s# = queue position, with padding + Insert an examples section + */ + } +} + static Glib::ustring makeFolderLabel(Glib::ustring path) { if (!Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) { @@ -158,13 +209,6 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) templateHelpTextView->set_wrap_mode(Gtk::WRAP_WORD); scrolledTemplateHelpWindow = Gtk::manage(new Gtk::ScrolledWindow()); scrolledTemplateHelpWindow->add(*templateHelpTextView); - { - auto helptext = M("QUEUE_LOCATION_TEMPLATE_TOOLTIP"); - auto buffer = templateHelpTextView->get_buffer(); - buffer->create_tag("bold"); - buffer->create_tag("italic"); - buffer->insert_markup(buffer->begin(), helptext); - } middleSplitPane->pack1 (*scrolledTemplateHelpWindow); middleSplitPane->pack2 (*batchQueue); scrolledTemplateHelpWindow->set_visible(false); // initially hidden, templateHelpButton shows it @@ -348,7 +392,11 @@ void BatchQueuePanel::setGuiFromBatchState(bool queueRunning, int qsize) void BatchQueuePanel::templateHelpButtonToggled() { bool visible = templateHelpButton->get_active(); - //scrolledTemplateHelpWindow->set_no_show_all(!visible); + auto buffer = templateHelpTextView->get_buffer(); + if (buffer->get_text().empty()) { + // Populate the help text the first time it's shown + populateTemplateHelpBuffer(buffer); + } scrolledTemplateHelpWindow->set_visible(visible); templateHelpTextView->set_visible(visible); } From ed5792bb9f496968007a0fbb39779c6d0668c4a7 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sat, 10 Feb 2024 13:49:19 -0500 Subject: [PATCH 06/22] Make populateTemplateHelpBuffer a private member of class BatchQueuePanel --- rtgui/batchqueuepanel.cc | 97 +++++++++++++++++++--------------------- rtgui/batchqueuepanel.h | 1 + 2 files changed, 47 insertions(+), 51 deletions(-) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 439134977..d150adc94 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -23,57 +23,6 @@ #include "soundman.h" #include "rtimage.h" -namespace // helper functions -{ - - // Populate the buffer of a Gtk::TextView with help text for the location template field - void populateTemplateHelpBuffer(Glib::RefPtr buffer) - { - auto pos = buffer->begin(); - auto insertHeading1 = [&pos, buffer](const Glib::ustring& text) { - pos = buffer->insert_markup(pos, Glib::ustring::format("", text, "\n")); - }; - auto insertHeading2 = [&pos, buffer](const Glib::ustring& text) { - pos = buffer->insert_markup(pos, Glib::ustring::format("\n\n", text, "\n")); - }; - insertHeading1(M("QUEUE_LOCATION_TEMPLATE_HELP_TITLE")); - pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_INTRO")); - insertHeading2(M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_TITLE")); - printf("[[[%s]]]", M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO").c_str()); - pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO")); - pos = buffer->insert(pos, "\n"); - pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_1")); -#ifdef _WIN32 - auto exampleString = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS"); -#else - auto exampleString = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX"); -#endif - pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleString, "\n")); - pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2")); - pos = buffer->insert(pos, "\n"); - /* FIXME: Still to do here: - Generate text like the original below, but use the actual conversion function to create it: - %d4 = %d-1 = home - %d3 = %d-2 = tom - %d2 = %d-3 = photos - %d1 = %d-4 = 2010-10-31 - %p1 = %p-4 = /home/tom/photos/2010-10-31/ - %p2 = %p-3 = /home/tom/photos/ - %p3 = %p-2 = /home/tom/ - %p4 = %p-1 = /home/ - %P1 = %P-4 = 2010-10-31/ - %P2 = %P-3 = photos/2010-10-31/ - %P3 = %P-2 = tom/photos/2010-10-31/ - %P4 = %P-1 = /home/tom/photos/2010-10-31/ - %f = photo1 - Insert sections for the remaining specifiers: - %r = rank - %s# = queue position, with padding - Insert an examples section - */ - } -} - static Glib::ustring makeFolderLabel(Glib::ustring path) { if (!Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) { @@ -401,6 +350,52 @@ void BatchQueuePanel::templateHelpButtonToggled() templateHelpTextView->set_visible(visible); } +void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr buffer) +{ + auto pos = buffer->begin(); + auto insertHeading1 = [&pos, buffer](const Glib::ustring& text) { + pos = buffer->insert_markup(pos, Glib::ustring::format("", text, "\n")); + }; + auto insertHeading2 = [&pos, buffer](const Glib::ustring& text) { + pos = buffer->insert_markup(pos, Glib::ustring::format("\n\n", text, "\n")); + }; + insertHeading1(M("QUEUE_LOCATION_TEMPLATE_HELP_TITLE")); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_INTRO")); + insertHeading2(M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_TITLE")); + printf("[[[%s]]]", M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO").c_str()); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO")); + pos = buffer->insert(pos, "\n"); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_1")); +#ifdef _WIN32 + auto exampleString = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS"); +#else + auto exampleString = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX"); +#endif + pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleString, "\n")); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2")); + pos = buffer->insert(pos, "\n"); + /* FIXME: Still to do here: + Generate text like the original below, but use the actual conversion function to create it: + %d4 = %d-1 = home + %d3 = %d-2 = tom + %d2 = %d-3 = photos + %d1 = %d-4 = 2010-10-31 + %p1 = %p-4 = /home/tom/photos/2010-10-31/ + %p2 = %p-3 = /home/tom/photos/ + %p3 = %p-2 = /home/tom/ + %p4 = %p-1 = /home/ + %P1 = %P-4 = 2010-10-31/ + %P2 = %P-3 = photos/2010-10-31/ + %P3 = %P-2 = tom/photos/2010-10-31/ + %P4 = %P-1 = /home/tom/photos/2010-10-31/ + %f = photo1 + Insert sections for the remaining specifiers: + %r = rank + %s# = queue position, with padding + Insert an examples section + */ +} + void BatchQueuePanel::addBatchQueueJobs(const std::vector& entries, bool head) { batchQueue->addEntries(entries, head); diff --git a/rtgui/batchqueuepanel.h b/rtgui/batchqueuepanel.h index bdd4ef6de..417d8a4cb 100644 --- a/rtgui/batchqueuepanel.h +++ b/rtgui/batchqueuepanel.h @@ -85,6 +85,7 @@ private: void startOrStopBatchProc(); void setGuiFromBatchState(bool queueRunning, int qsize); void templateHelpButtonToggled(); + void populateTemplateHelpBuffer(Glib::RefPtr buffer); void pathFolderChanged (); void pathFolderButtonPressed (); From 2690e27dea191af5f6cd3ded978fc314fe9cd596 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 11 Feb 2024 14:03:58 -0500 Subject: [PATCH 07/22] Generate help examples (Windows or Linux, as appropriate) for %d, %p and %P specifiers. Also make the help pane half the overall width when first shown (and it's resizeable). --- rtdata/languages/default | 4 +- rtgui/batchqueuepanel.cc | 85 +++++++++++++++++++++++++++++++--------- 2 files changed, 69 insertions(+), 20 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index b2c1cf890..4129bf314 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2111,11 +2111,13 @@ QUEUE_LOCATION_TEMPLATE_TOOLTIP;Specify the output location based on characteris QUEUE_LOCATION_TEMPLATE_HELP_TITLE;Creating an output template QUEUE_LOCATION_TEMPLATE_HELP_INTRO;The output template field allows you to to dynamically customize the destination folder and filename. When you include certain specifiers, which begin with %, they are replaced by the program when each file is being saved.\n\nThe sections below describe each type of specifier. QUEUE_LOCATION_TEMPLATE_HELP_PATHS_TITLE;Directories and partial paths -QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO;The %dN, %d-N, %pN, %p-N, %PN and %P-N (N = 1..9) specifiers will be replaced by elements of the image file's directory path.\nThe format specifiers operate as follows:\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. +QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO;The %dN, %d-N, %pN, %p-N, %PN and %P-N (N = 1..9) specifiers will be replaced by elements of the image file's directory path.\nThe format specifiers operate as follows:\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) +QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO_WINDOWS;For Windows paths, %d-1 is the drive letter and colon, and %d-2 is the base directory on that drive. QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_1;Using this pathname as an example: QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX;/home/tom/photos/2010-10-31/photo1.raw QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS;C:\users\tom\photos\2010-10-31\photo1.raw QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2;The meanings of the formatting strings are: +QUEUE_LOCATION_TEMPLATE_HELP_RESULT_MISMATCH;ERROR: 2nd result is different: QUEUE_LOCATION_TITLE;Output Location QUEUE_STARTSTOP_TOOLTIP;Start or stop processing the images in the queue.\n\nShortcut: Ctrl+s diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index d150adc94..f4e97689b 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -1,3 +1,4 @@ +#define CHECKPOINT printf("CHECKPOINT: %d\n", __LINE__); // FIXME: REMOVE /* * This file is part of RawTherapee. * @@ -345,6 +346,8 @@ void BatchQueuePanel::templateHelpButtonToggled() if (buffer->get_text().empty()) { // Populate the help text the first time it's shown populateTemplateHelpBuffer(buffer); + auto fullWidth = middleSplitPane->get_width(); + middleSplitPane->set_position(fullWidth / 2); } scrolledTemplateHelpWindow->set_visible(visible); templateHelpTextView->set_visible(visible); @@ -362,38 +365,82 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b insertHeading1(M("QUEUE_LOCATION_TEMPLATE_HELP_TITLE")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_INTRO")); insertHeading2(M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_TITLE")); - printf("[[[%s]]]", M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO").c_str()); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO")); pos = buffer->insert(pos, "\n"); +#ifdef _WIN32 + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO_WINDOWS")); + pos = buffer->insert(pos, "\n"); +#endif + pos = buffer->insert(pos, "\n"); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_1")); #ifdef _WIN32 - auto exampleString = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS"); + auto exampleFilePath = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS"); #else - auto exampleString = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX"); + auto exampleFilePath = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX"); #endif - pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleString, "\n")); + pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleFilePath, "\n")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2")); - pos = buffer->insert(pos, "\n"); + // Examples are generated from exampleFilePath using the actual template processing function + Options savedOptions = options; // to be restored after generating example results + options.saveUsePathTemplate = true; + // Since this code only ever runs once (the first time the help text is presented), no attempt is + // made to be efficient. Use a brute-force method to discover the number of elements in exampleFilePath. + int pathElementCount = 0; + for (int n=9; n>=0; n--) + { + options.savePathTemplate = Glib::ustring::format("%d",n); + auto result = BatchQueue::calcAutoFileNameBase(exampleFilePath); + if (!result.empty()) + { + // The 'd' specifier returns an empty string if N exceeds the number of path elements, so + // the largest N that does not return an empty string is the number of elements in exampleFilePath. + pathElementCount = n; + break; + } + } + // Function inserts examples for a particular specifier, with every valid N value for the + // number of elements in the path. + auto insertPathExamples = [&buffer, &pos, pathElementCount, exampleFilePath](char letter, int offset1, int mult1, int offset2, int mult2) + { + Glib::ustring startMonospace(""); + Glib::ustring endMonospace(""); + auto buildBuffer = Gtk::TextBuffer::create(); + auto buildpos = buildBuffer->begin(); + buildpos = buildBuffer->insert(buildpos, startMonospace); + for (int n=0; n%d4 = %d-1 = home + auto path1 = Glib::ustring::format("%",letter,offset1+n*mult1); + auto path2 = Glib::ustring::format("%",letter,offset2+n*mult2); + options.savePathTemplate = path1; + auto result1 = BatchQueue::calcAutoFileNameBase(exampleFilePath); + options.savePathTemplate = path2; + auto result2 = BatchQueue::calcAutoFileNameBase(exampleFilePath); + buildpos = buildBuffer->insert (buildpos, Glib::ustring::format("\n ", path1, " = ", path2, " = ", result1, "")); + if (result1 != result2) + { + buildpos = buildBuffer->insert(buildpos, Glib::ustring::format(" ", M("QUEUE_LOCATION_TEMPLATE_HELP_RESULT_MISMATCH"), " ", result2)); + } + } + buildpos = buildBuffer->insert(buildpos, endMonospace); + pos = buffer->insert_markup(pos, buildBuffer->get_text()); + }; + // Example outputs in comments below are for a 4-element path. + // %d4 = %d-1 = home + insertPathExamples('d', pathElementCount, -1, -1, -1); + // %p1 = %p-4 = /home/tom/photos/2010-10-31/ + insertPathExamples('p', 1, 1, -pathElementCount, 1); + // %P1 = %P-4 = 2010-10-31/ + insertPathExamples('P', 1, 1, -pathElementCount, 1); + /* FIXME: Still to do here: - Generate text like the original below, but use the actual conversion function to create it: - %d4 = %d-1 = home - %d3 = %d-2 = tom - %d2 = %d-3 = photos - %d1 = %d-4 = 2010-10-31 - %p1 = %p-4 = /home/tom/photos/2010-10-31/ - %p2 = %p-3 = /home/tom/photos/ - %p3 = %p-2 = /home/tom/ - %p4 = %p-1 = /home/ - %P1 = %P-4 = 2010-10-31/ - %P2 = %P-3 = photos/2010-10-31/ - %P3 = %P-2 = tom/photos/2010-10-31/ - %P4 = %P-1 = /home/tom/photos/2010-10-31/ - %f = photo1 Insert sections for the remaining specifiers: %r = rank %s# = queue position, with padding Insert an examples section */ + options = savedOptions; } void BatchQueuePanel::addBatchQueueJobs(const std::vector& entries, bool head) From 353a4d472a27845186a16c180f70452e42975427 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 11 Feb 2024 14:28:03 -0500 Subject: [PATCH 08/22] Added help sections for %r and %s tags, and for common examples --- rtdata/languages/default | 8 ++++++-- rtgui/batchqueuepanel.cc | 30 ++++++++++++++++++------------ 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 4129bf314..ee08b0ba7 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2106,7 +2106,6 @@ 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 -REMOVE_ME_OLD___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_TEMPLATE_TOOLTIP;Specify the output location based on characteristics such as the source photo's location, rank, trash status or position in the queue.\n\nThe output template field value can include specifiers beginning with %, which are replaced by those characteristics in the actual destination path.\n\nPress the ? button for full instructions. QUEUE_LOCATION_TEMPLATE_HELP_TITLE;Creating an output template QUEUE_LOCATION_TEMPLATE_HELP_INTRO;The output template field allows you to to dynamically customize the destination folder and filename. When you include certain specifiers, which begin with %, they are replaced by the program when each file is being saved.\n\nThe sections below describe each type of specifier. @@ -2118,7 +2117,12 @@ QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX;/home/tom/photos/2010-10-31/pho QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS;C:\users\tom\photos\2010-10-31\photo1.raw QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2;The meanings of the formatting strings are: QUEUE_LOCATION_TEMPLATE_HELP_RESULT_MISMATCH;ERROR: 2nd result is different: - +QUEUE_LOCATION_TEMPLATE_HELP_RANK_TITLE;Rank +QUEUE_LOCATION_TEMPLATE_HELP_RANK_BODY;%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. +QUEUE_LOCATION_TEMPLATE_HELP_SEQUENCE_TITLE;Position/sequence in queue +QUEUE_LOCATION_TEMPLATE_HELP_SEQUENCE_BODY;%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'. +QUEUE_LOCATION_TEMPLATE_HELP_EXAMPLES_TITLE;Common examples +QUEUE_LOCATION_TEMPLATE_HELP_EXAMPLES_BODY;If 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 diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index f4e97689b..a0587d442 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -356,15 +356,16 @@ void BatchQueuePanel::templateHelpButtonToggled() void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr buffer) { auto pos = buffer->begin(); - auto insertHeading1 = [&pos, buffer](const Glib::ustring& text) { - pos = buffer->insert_markup(pos, Glib::ustring::format("", text, "\n")); - }; - auto insertHeading2 = [&pos, buffer](const Glib::ustring& text) { + auto insertTopicHeading = [&pos, buffer](const Glib::ustring& text) { pos = buffer->insert_markup(pos, Glib::ustring::format("\n\n", text, "\n")); }; - insertHeading1(M("QUEUE_LOCATION_TEMPLATE_HELP_TITLE")); + auto insertTopicBody = [&pos, buffer](const Glib::ustring& text) { + pos = buffer->insert_markup(pos, Glib::ustring::format("\n", text, "\n")); + }; + auto mainTitle = M("QUEUE_LOCATION_TEMPLATE_HELP_TITLE"); + pos = buffer->insert_markup(pos, Glib::ustring::format("", mainTitle, "\n")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_INTRO")); - insertHeading2(M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_TITLE")); + insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_TITLE")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO")); pos = buffer->insert(pos, "\n"); #ifdef _WIN32 @@ -409,8 +410,6 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b buildpos = buildBuffer->insert(buildpos, startMonospace); for (int n=0; n%d4 = %d-1 = home auto path1 = Glib::ustring::format("%",letter,offset1+n*mult1); auto path2 = Glib::ustring::format("%",letter,offset2+n*mult2); options.savePathTemplate = path1; @@ -420,6 +419,8 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b buildpos = buildBuffer->insert (buildpos, Glib::ustring::format("\n ", path1, " = ", path2, " = ", result1, "")); if (result1 != result2) { + // If this error appears, it indicates a coding error in either BatchQueue::calcAutoFileNameBase + // or BatchQueuePanel::populateTemplateHelpBuffer. buildpos = buildBuffer->insert(buildpos, Glib::ustring::format(" ", M("QUEUE_LOCATION_TEMPLATE_HELP_RESULT_MISMATCH"), " ", result2)); } } @@ -434,11 +435,16 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b // %P1 = %P-4 = 2010-10-31/ insertPathExamples('P', 1, 1, -pathElementCount, 1); + insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_RANK_TITLE")); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_RANK_BODY")); + + insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_SEQUENCE_TITLE")); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_SEQUENCE_BODY")); + + insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_EXAMPLES_TITLE")); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_EXAMPLES_BODY")); /* FIXME: Still to do here: - Insert sections for the remaining specifiers: - %r = rank - %s# = queue position, with padding - Insert an examples section + Insert section for time/date specifiers */ options = savedOptions; } From bc054ea5065523b61526d19f27eb4098a381a299 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 11 Feb 2024 15:07:50 -0500 Subject: [PATCH 09/22] Added help for time/date template specifiers --- rtdata/languages/default | 2 ++ rtgui/batchqueuepanel.cc | 26 +++++++++++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index ee08b0ba7..00c3089d7 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2121,6 +2121,8 @@ QUEUE_LOCATION_TEMPLATE_HELP_RANK_TITLE;Rank QUEUE_LOCATION_TEMPLATE_HELP_RANK_BODY;%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. QUEUE_LOCATION_TEMPLATE_HELP_SEQUENCE_TITLE;Position/sequence in queue QUEUE_LOCATION_TEMPLATE_HELP_SEQUENCE_BODY;%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'. +QUEUE_LOCATION_TEMPLATE_HELP_TIMESTAMP_TITLE;Date and time +QUEUE_LOCATION_TEMPLATE_HELP_TIMESTAMP_BODY;Three different date/time values may be used in templates:\n %tE"%Y-%m-%d" = when export started\n %tF"%Y-%m-%d" = when file was last saved\n %tP"%Y-%m-%d" = when photo was taken\nThe quoted string defines the format of the resulting date and/or time. The format string %tF"%Y-%m-%d" is just one example. The string can use all conversion specifiers defined for the g_date_time_format function (see https://docs.gtk.org/glib/method.DateTime.format.html).\n\nExample format strings: QUEUE_LOCATION_TEMPLATE_HELP_EXAMPLES_TITLE;Common examples QUEUE_LOCATION_TEMPLATE_HELP_EXAMPLES_BODY;If 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 diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index a0587d442..9935da212 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -1,4 +1,3 @@ -#define CHECKPOINT printf("CHECKPOINT: %d\n", __LINE__); // FIXME: REMOVE /* * This file is part of RawTherapee. * @@ -365,6 +364,10 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b auto mainTitle = M("QUEUE_LOCATION_TEMPLATE_HELP_TITLE"); pos = buffer->insert_markup(pos, Glib::ustring::format("", mainTitle, "\n")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_INTRO")); + + insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_EXAMPLES_TITLE")); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_EXAMPLES_BODY")); + insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_TITLE")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO")); pos = buffer->insert(pos, "\n"); @@ -441,12 +444,21 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_SEQUENCE_TITLE")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_SEQUENCE_BODY")); - insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_EXAMPLES_TITLE")); - pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_EXAMPLES_BODY")); - /* FIXME: Still to do here: - Insert section for time/date specifiers - */ - options = savedOptions; + insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_TIMESTAMP_TITLE")); + pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_TIMESTAMP_BODY")); + Glib::ustring dateTimeFormatExamples[] = { + "%Y-%m-%d", + "%Y%m%d_%H%M%S", + "%y/%b/%-d/" + }; + auto timeNow = Glib::DateTime::create_now_local(); + for (auto fmt : dateTimeFormatExamples) { + auto result = timeNow.format(fmt); + pos = buffer->insert_markup(pos, Glib::ustring::format("\n %tE\"", fmt, "\" = ", result, "")); + } + + pos = buffer->insert(pos, "\n"); + options = savedOptions; // Do not add any lines in this function below here } void BatchQueuePanel::addBatchQueueJobs(const std::vector& entries, bool head) From ccc667e3905f305e908f12df00e1eba2d083d8b3 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 11 Feb 2024 15:10:02 -0500 Subject: [PATCH 10/22] Added specific tooltip for the location template "?" help toggle button --- rtdata/languages/default | 1 + rtgui/batchqueuepanel.cc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 00c3089d7..e5ce63a20 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2107,6 +2107,7 @@ 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 characteristics such as the source photo's location, rank, trash status or position in the queue.\n\nThe output template field value can include specifiers beginning with %, which are replaced by those characteristics in the actual destination path.\n\nPress the ? button for full instructions. +QUEUE_LOCATION_TEMPLATE_HELP_BUTTON_TOOLTIP;Show or hide a help panel with instructions for creating location templates QUEUE_LOCATION_TEMPLATE_HELP_TITLE;Creating an output template QUEUE_LOCATION_TEMPLATE_HELP_INTRO;The output template field allows you to to dynamically customize the destination folder and filename. When you include certain specifiers, which begin with %, they are replaced by the program when each file is being saved.\n\nThe sections below describe each type of specifier. QUEUE_LOCATION_TEMPLATE_HELP_PATHS_TITLE;Directories and partial paths diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 9935da212..991ff0239 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -74,7 +74,7 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) outdirTemplate = Gtk::manage (new Gtk::Entry ()); hb2->pack_start (*outdirTemplate); templateHelpButton = Gtk::manage (new Gtk::ToggleButton("?")); - templateHelpButton->set_tooltip_markup (M ("GENERAL_HELP")); // FIXME: Specific tooltip for this button + templateHelpButton->set_tooltip_markup (M ("QUEUE_LOCATION_TEMPLATE_HELP_BUTTON_TOOLTIP")); hb2->pack_start (*templateHelpButton, Gtk::PACK_SHRINK, 0); odvb->pack_start (*hb2, Gtk::PACK_SHRINK, 0); outdirTemplate->set_tooltip_markup (M("QUEUE_LOCATION_TEMPLATE_TOOLTIP")); From 5d7586bab4be69ab23614c79af080e199cd10355 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 11 Feb 2024 15:28:39 -0500 Subject: [PATCH 11/22] Simplify path help, add '%f' to generated examples --- rtdata/languages/default | 2 +- rtgui/batchqueuepanel.cc | 26 +++++++++++--------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index e5ce63a20..b089b69cb 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2115,7 +2115,7 @@ QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO;The %dN, %d-N, %pN QUEUE_LOCATION_TEMPLATE_HELP_PATHS_INTRO_WINDOWS;For Windows paths, %d-1 is the drive letter and colon, and %d-2 is the base directory on that drive. QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_1;Using this pathname as an example: QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX;/home/tom/photos/2010-10-31/photo1.raw -QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS;C:\users\tom\photos\2010-10-31\photo1.raw +QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS;D:\tom\photos\2010-10-31\photo1.raw QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2;The meanings of the formatting strings are: QUEUE_LOCATION_TEMPLATE_HELP_RESULT_MISMATCH;ERROR: 2nd result is different: QUEUE_LOCATION_TEMPLATE_HELP_RANK_TITLE;Rank diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 991ff0239..1fa0b7169 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -406,11 +406,6 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b // number of elements in the path. auto insertPathExamples = [&buffer, &pos, pathElementCount, exampleFilePath](char letter, int offset1, int mult1, int offset2, int mult2) { - Glib::ustring startMonospace(""); - Glib::ustring endMonospace(""); - auto buildBuffer = Gtk::TextBuffer::create(); - auto buildpos = buildBuffer->begin(); - buildpos = buildBuffer->insert(buildpos, startMonospace); for (int n=0; n b auto result1 = BatchQueue::calcAutoFileNameBase(exampleFilePath); options.savePathTemplate = path2; auto result2 = BatchQueue::calcAutoFileNameBase(exampleFilePath); - buildpos = buildBuffer->insert (buildpos, Glib::ustring::format("\n ", path1, " = ", path2, " = ", result1, "")); + pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", path1, " = ", path2, " = ", result1, "")); if (result1 != result2) { // If this error appears, it indicates a coding error in either BatchQueue::calcAutoFileNameBase // or BatchQueuePanel::populateTemplateHelpBuffer. - buildpos = buildBuffer->insert(buildpos, Glib::ustring::format(" ", M("QUEUE_LOCATION_TEMPLATE_HELP_RESULT_MISMATCH"), " ", result2)); + pos = buffer->insert_markup(pos, Glib::ustring::format(" ", M("QUEUE_LOCATION_TEMPLATE_HELP_RESULT_MISMATCH"), " ", result2)); } } - buildpos = buildBuffer->insert(buildpos, endMonospace); - pos = buffer->insert_markup(pos, buildBuffer->get_text()); }; // Example outputs in comments below are for a 4-element path. - // %d4 = %d-1 = home - insertPathExamples('d', pathElementCount, -1, -1, -1); - // %p1 = %p-4 = /home/tom/photos/2010-10-31/ - insertPathExamples('p', 1, 1, -pathElementCount, 1); - // %P1 = %P-4 = 2010-10-31/ - insertPathExamples('P', 1, 1, -pathElementCount, 1); + insertPathExamples('d', pathElementCount, -1, -1, -1); // %d4 = %d-1 = home + insertPathExamples('p', 1, 1, -pathElementCount, 1); // %p1 = %p-4 = /home/tom/photos/2010-10-31/ + insertPathExamples('P', 1, 1, -pathElementCount, 1); // %P1 = %P-4 = 2010-10-31/ + { + Glib::ustring fspecifier("%f"); + options.savePathTemplate = fspecifier; + auto result = BatchQueue::calcAutoFileNameBase(exampleFilePath); + pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", fspecifier, " = ", result, "")); + } insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_RANK_TITLE")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_RANK_BODY")); From 79134ecc9f85f9f772faffcd9be70945f69b273d Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Mon, 12 Feb 2024 17:06:08 -0500 Subject: [PATCH 12/22] Instead of time now, in help examples use 2001-02-03T04:05:06.123456 local time --- rtgui/batchqueuepanel.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 1fa0b7169..f234c734c 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -447,9 +447,10 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b "%Y%m%d_%H%M%S", "%y/%b/%-d/" }; - auto timeNow = Glib::DateTime::create_now_local(); + auto timezone = Glib::DateTime::create_now_local().get_timezone(); + auto timeForExamples = Glib::DateTime::create_from_iso8601("2001-02-03T04:05:06.123456", timezone); for (auto fmt : dateTimeFormatExamples) { - auto result = timeNow.format(fmt); + auto result = timeForExamples.format(fmt); pos = buffer->insert_markup(pos, Glib::ustring::format("\n %tE\"", fmt, "\" = ", result, "")); } From dbd0829e61f541b787cc353a3caabf23bfa065ef Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Mon, 12 Feb 2024 18:35:01 -0500 Subject: [PATCH 13/22] Obtain the export, shooting or save time, per letter after %t output template specifier Print the result (not yet processing a time formatting string) --- rtgui/batchqueue.cc | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 2811e3445..8654ce45e 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -18,8 +18,10 @@ */ #include #include +#include #include #include +#include "../rtengine/imagedata.h" #include "../rtengine/rt_math.h" #include "../rtengine/procparams.h" @@ -1001,6 +1003,45 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam seqstr << sequence; path += seqstr.str (); + } else if (options.savePathTemplate[ix] == 't') { + // Insert formatted date/time value. Character after 't' defines time source + if (++ix < options.savePathTemplate.size()) + { + Glib::DateTime dateTime; + bool dateTimeIsValid = true; + switch(options.savePathTemplate[ix]) + { + case 'E': // (approximate) time when export started + dateTime = Glib::DateTime::create_now_local(); + break; + case 'F': // time when file was last saved + { + struct stat fileStat; + if (stat(origFileName.c_str(), &fileStat) == 0) { + time_t timestamp = fileStat.st_mtime; + dateTime = Glib::DateTime::create_now_local(timestamp); + } else { + dateTimeIsValid = false; // file not found, access denied, etc. + } + } + break; + case 'P': // time when picture was taken + { + auto timestamp = FramesData(origFileName).getDateTimeAsTS(); + dateTime = Glib::DateTime::create_now_local(timestamp); + } + break; + default: + dateTimeIsValid = false; + break; + } + if (dateTimeIsValid) + { + // FIXME: Call a function that looks for a double-quoted format string, and + // format dateTime accordingly, adding it to path. + printf("Time %s\n", dateTime.format_iso8601().c_str()); + } + } } } From 94cd3d46265b2d4009005305c390405bcc5f7b82 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 18 Feb 2024 11:30:43 -0500 Subject: [PATCH 14/22] Apply time/date format for %t output template specifier --- rtgui/batchqueue.cc | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 8654ce45e..df7842bc7 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -96,6 +96,21 @@ namespace // local helper functions } } } + + // Look in templateText at index ix for quoted string containing a time format string, and + // use that string to format dateTime. Append the formatted time to path. + void appendFormattedTime(Glib::ustring& path, unsigned int& ix, Glib::ustring& templateText, const Glib::DateTime& dateTime) + { + constexpr unsigned int quoteMark = (unsigned int)'"'; + if ((ix + 1) < templateText.size() && templateText[ix] == quoteMark) { + auto endPos = templateText.find_first_of(quoteMark, ++ix); + if (endPos != Glib::ustring::npos) { + Glib::ustring formatString(templateText, ix, endPos-ix); + path += dateTime.format(formatString); + ix = endPos; + } + } + } } BatchQueue::BatchQueue (FileCatalog* aFileCatalog) : processing(nullptr), fileCatalog(aFileCatalog), sequence(0), listener(nullptr) @@ -1009,7 +1024,7 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam { Glib::DateTime dateTime; bool dateTimeIsValid = true; - switch(options.savePathTemplate[ix]) + switch(options.savePathTemplate[ix++]) { case 'E': // (approximate) time when export started dateTime = Glib::DateTime::create_now_local(); @@ -1037,9 +1052,7 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam } if (dateTimeIsValid) { - // FIXME: Call a function that looks for a double-quoted format string, and - // format dateTime accordingly, adding it to path. - printf("Time %s\n", dateTime.format_iso8601().c_str()); + appendFormattedTime(path, ix, options.savePathTemplate, dateTime); } } } From 703a81ae0c005c6b19350dacf71bd5180aed000a Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 18 Feb 2024 12:22:36 -0500 Subject: [PATCH 15/22] Removed FIXME comment --- rtgui/batchqueuepanel.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index f234c734c..2daccc5ec 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -151,7 +151,6 @@ BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) : parent(nullptr) topBox->pack_start (*fdir, Gtk::PACK_EXPAND_WIDGET, 4); topBox->pack_start (*fformat, Gtk::PACK_EXPAND_WIDGET, 4); - // FIXME: THIS IS SO FAR JUST A TEST THING middleSplitPane = Gtk::manage (new Gtk::Paned(Gtk::ORIENTATION_HORIZONTAL)); templateHelpTextView = Gtk::manage (new Gtk::TextView()); templateHelpTextView->set_editable(false); From 547ac41ad4b236cf311c1870ee80050e9144e7f2 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 18 Feb 2024 12:28:00 -0500 Subject: [PATCH 16/22] Make brace placement consistent --- rtgui/batchqueue.cc | 6 ++---- rtgui/batchqueuepanel.cc | 12 ++++-------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index df7842bc7..622124be4 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -1020,8 +1020,7 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam path += seqstr.str (); } else if (options.savePathTemplate[ix] == 't') { // Insert formatted date/time value. Character after 't' defines time source - if (++ix < options.savePathTemplate.size()) - { + if (++ix < options.savePathTemplate.size()) { Glib::DateTime dateTime; bool dateTimeIsValid = true; switch(options.savePathTemplate[ix++]) @@ -1050,8 +1049,7 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam dateTimeIsValid = false; break; } - if (dateTimeIsValid) - { + if (dateTimeIsValid) { appendFormattedTime(path, ix, options.savePathTemplate, dateTime); } } diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 2daccc5ec..b74998738 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -389,12 +389,10 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b // Since this code only ever runs once (the first time the help text is presented), no attempt is // made to be efficient. Use a brute-force method to discover the number of elements in exampleFilePath. int pathElementCount = 0; - for (int n=9; n>=0; n--) - { + for (int n=9; n>=0; n--) { options.savePathTemplate = Glib::ustring::format("%d",n); auto result = BatchQueue::calcAutoFileNameBase(exampleFilePath); - if (!result.empty()) - { + if (!result.empty()) { // The 'd' specifier returns an empty string if N exceeds the number of path elements, so // the largest N that does not return an empty string is the number of elements in exampleFilePath. pathElementCount = n; @@ -405,8 +403,7 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b // number of elements in the path. auto insertPathExamples = [&buffer, &pos, pathElementCount, exampleFilePath](char letter, int offset1, int mult1, int offset2, int mult2) { - for (int n=0; n b options.savePathTemplate = path2; auto result2 = BatchQueue::calcAutoFileNameBase(exampleFilePath); pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", path1, " = ", path2, " = ", result1, "")); - if (result1 != result2) - { + if (result1 != result2) { // If this error appears, it indicates a coding error in either BatchQueue::calcAutoFileNameBase // or BatchQueuePanel::populateTemplateHelpBuffer. pos = buffer->insert_markup(pos, Glib::ustring::format(" ", M("QUEUE_LOCATION_TEMPLATE_HELP_RESULT_MISMATCH"), " ", result2)); From b39ab15659ebc26701157731b6089b832a596ffd Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Mon, 19 Feb 2024 11:35:46 -0500 Subject: [PATCH 17/22] Eliminated use of stat() instead using Gio::FileInfo to get file modification date --- rtgui/batchqueue.cc | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 622124be4..2d46d9766 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -18,7 +18,6 @@ */ #include #include -#include #include #include #include "../rtengine/imagedata.h" @@ -99,7 +98,7 @@ namespace // local helper functions // Look in templateText at index ix for quoted string containing a time format string, and // use that string to format dateTime. Append the formatted time to path. - void appendFormattedTime(Glib::ustring& path, unsigned int& ix, Glib::ustring& templateText, const Glib::DateTime& dateTime) + void appendFormattedTime(Glib::ustring& path, unsigned int& ix, const Glib::ustring& templateText, const Glib::DateTime& dateTime) { constexpr unsigned int quoteMark = (unsigned int)'"'; if ((ix + 1) < templateText.size() && templateText[ix] == quoteMark) { @@ -1030,12 +1029,16 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam break; case 'F': // time when file was last saved { - struct stat fileStat; - if (stat(origFileName.c_str(), &fileStat) == 0) { - time_t timestamp = fileStat.st_mtime; - dateTime = Glib::DateTime::create_now_local(timestamp); - } else { - dateTimeIsValid = false; // file not found, access denied, etc. + dateTimeIsValid = false; // becomes true below if no errors + Glib::RefPtr file = Gio::File::create_for_path(origFileName); + if (file) { + Glib::RefPtr info = file->query_info("time::modified"); + if (info) { + dateTime = info->get_modification_date_time(); + if (dateTime) { + dateTimeIsValid = true; + } + } } } break; From 7c67739b9de12f3dff9847ca15af7d2b34c11e60 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Mon, 19 Feb 2024 11:43:04 -0500 Subject: [PATCH 18/22] Eliminated dateTimeIsValid, instead null-checking dateTime -- non-null means it's valid. --- rtgui/batchqueue.cc | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 2d46d9766..ab9c14c7c 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -1021,7 +1021,6 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam // Insert formatted date/time value. Character after 't' defines time source if (++ix < options.savePathTemplate.size()) { Glib::DateTime dateTime; - bool dateTimeIsValid = true; switch(options.savePathTemplate[ix++]) { case 'E': // (approximate) time when export started @@ -1029,15 +1028,11 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam break; case 'F': // time when file was last saved { - dateTimeIsValid = false; // becomes true below if no errors Glib::RefPtr file = Gio::File::create_for_path(origFileName); if (file) { Glib::RefPtr info = file->query_info("time::modified"); if (info) { dateTime = info->get_modification_date_time(); - if (dateTime) { - dateTimeIsValid = true; - } } } } @@ -1049,10 +1044,9 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam } break; default: - dateTimeIsValid = false; break; } - if (dateTimeIsValid) { + if (dateTime) { appendFormattedTime(path, ix, options.savePathTemplate, dateTime); } } From fbeaace607d5ecdd207d49a4523025335d1d97fb Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 25 Feb 2024 10:14:10 -0500 Subject: [PATCH 19/22] Change literal to G_FILE_ATTRIBUTE_TIME_MODIFIED, change line spacing in template help --- rtgui/batchqueue.cc | 2 +- rtgui/batchqueuepanel.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index ab9c14c7c..3a82ef511 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -1030,7 +1030,7 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam { Glib::RefPtr file = Gio::File::create_for_path(origFileName); if (file) { - Glib::RefPtr info = file->query_info("time::modified"); + Glib::RefPtr info = file->query_info(G_FILE_ATTRIBUTE_TIME_MODIFIED); if (info) { dateTime = info->get_modification_date_time(); } diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index b74998738..619a5f896 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -381,7 +381,7 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b #else auto exampleFilePath = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX"); #endif - pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleFilePath, "\n")); + pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleFilePath, "\n\n")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2")); // Examples are generated from exampleFilePath using the actual template processing function Options savedOptions = options; // to be restored after generating example results From 50f27c099cb2443286c2ec4170afd185f7c27d79 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 25 Feb 2024 17:38:42 -0500 Subject: [PATCH 20/22] Make indentation consistent in queue template help --- rtgui/batchqueuepanel.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 619a5f896..27df872d3 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -381,7 +381,7 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b #else auto exampleFilePath = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX"); #endif - pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleFilePath, "\n\n")); + pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleFilePath, "\n")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2")); // Examples are generated from exampleFilePath using the actual template processing function Options savedOptions = options; // to be restored after generating example results @@ -410,7 +410,7 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b auto result1 = BatchQueue::calcAutoFileNameBase(exampleFilePath); options.savePathTemplate = path2; auto result2 = BatchQueue::calcAutoFileNameBase(exampleFilePath); - pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", path1, " = ", path2, " = ", result1, "")); + pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", path1, " = ", path2, " = ", result1, "")); if (result1 != result2) { // If this error appears, it indicates a coding error in either BatchQueue::calcAutoFileNameBase // or BatchQueuePanel::populateTemplateHelpBuffer. @@ -426,7 +426,7 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b Glib::ustring fspecifier("%f"); options.savePathTemplate = fspecifier; auto result = BatchQueue::calcAutoFileNameBase(exampleFilePath); - pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", fspecifier, " = ", result, "")); + pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", fspecifier, " = ", result, "")); } insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_RANK_TITLE")); @@ -446,7 +446,7 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b auto timeForExamples = Glib::DateTime::create_from_iso8601("2001-02-03T04:05:06.123456", timezone); for (auto fmt : dateTimeFormatExamples) { auto result = timeForExamples.format(fmt); - pos = buffer->insert_markup(pos, Glib::ustring::format("\n %tE\"", fmt, "\" = ", result, "")); + pos = buffer->insert_markup(pos, Glib::ustring::format("\n %tE\"", fmt, "\" = ", result, "")); } pos = buffer->insert(pos, "\n"); From 1db8b0d64323144baf83db6abc9b546add2b6ff3 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Sun, 25 Feb 2024 17:49:00 -0500 Subject: [PATCH 21/22] Indent example path the same amount as other indented items in the queue template help --- rtgui/batchqueuepanel.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 27df872d3..f7e46fa7c 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -381,7 +381,7 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b #else auto exampleFilePath = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX"); #endif - pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleFilePath, "\n")); + pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleFilePath, "\n")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2")); // Examples are generated from exampleFilePath using the actual template processing function Options savedOptions = options; // to be restored after generating example results From cd64ced60fd4053c1603ec55f2e2ef6ab5c1aaa0 Mon Sep 17 00:00:00 2001 From: Scott Gilbertson Date: Wed, 28 Feb 2024 13:09:25 -0500 Subject: [PATCH 22/22] Address comments in pull request: - use "const" where possible - add spaces after commas - use dateTimeFormatExamples by reference (don't copy) - fix incorrect cast to unsigned int (declare variable as gunichar) --- rtgui/batchqueue.cc | 14 +++++++++----- rtgui/batchqueuepanel.cc | 38 +++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 3a82ef511..c275ee675 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -100,9 +100,9 @@ namespace // local helper functions // use that string to format dateTime. Append the formatted time to path. void appendFormattedTime(Glib::ustring& path, unsigned int& ix, const Glib::ustring& templateText, const Glib::DateTime& dateTime) { - constexpr unsigned int quoteMark = (unsigned int)'"'; + constexpr gunichar quoteMark('"'); if ((ix + 1) < templateText.size() && templateText[ix] == quoteMark) { - auto endPos = templateText.find_first_of(quoteMark, ++ix); + const auto endPos = templateText.find_first_of(quoteMark, ++ix); if (endPos != Glib::ustring::npos) { Glib::ustring formatString(templateText, ix, endPos-ix); path += dateTime.format(formatString); @@ -1024,8 +1024,10 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam switch(options.savePathTemplate[ix++]) { case 'E': // (approximate) time when export started + { dateTime = Glib::DateTime::create_now_local(); break; + } case 'F': // time when file was last saved { Glib::RefPtr file = Gio::File::create_for_path(origFileName); @@ -1035,16 +1037,18 @@ Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileNam dateTime = info->get_modification_date_time(); } } - } break; + } case 'P': // time when picture was taken { - auto timestamp = FramesData(origFileName).getDateTimeAsTS(); + const auto timestamp = FramesData(origFileName).getDateTimeAsTS(); dateTime = Glib::DateTime::create_now_local(timestamp); + break; } - break; default: + { break; + } } if (dateTime) { appendFormattedTime(path, ix, options.savePathTemplate, dateTime); diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index f7e46fa7c..bf6cc0772 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -344,7 +344,7 @@ void BatchQueuePanel::templateHelpButtonToggled() if (buffer->get_text().empty()) { // Populate the help text the first time it's shown populateTemplateHelpBuffer(buffer); - auto fullWidth = middleSplitPane->get_width(); + const auto fullWidth = middleSplitPane->get_width(); middleSplitPane->set_position(fullWidth / 2); } scrolledTemplateHelpWindow->set_visible(visible); @@ -354,13 +354,13 @@ void BatchQueuePanel::templateHelpButtonToggled() void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr buffer) { auto pos = buffer->begin(); - auto insertTopicHeading = [&pos, buffer](const Glib::ustring& text) { + const auto insertTopicHeading = [&pos, buffer](const Glib::ustring& text) { pos = buffer->insert_markup(pos, Glib::ustring::format("\n\n", text, "\n")); }; - auto insertTopicBody = [&pos, buffer](const Glib::ustring& text) { + const auto insertTopicBody = [&pos, buffer](const Glib::ustring& text) { pos = buffer->insert_markup(pos, Glib::ustring::format("\n", text, "\n")); }; - auto mainTitle = M("QUEUE_LOCATION_TEMPLATE_HELP_TITLE"); + const auto mainTitle = M("QUEUE_LOCATION_TEMPLATE_HELP_TITLE"); pos = buffer->insert_markup(pos, Glib::ustring::format("", mainTitle, "\n")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_INTRO")); @@ -377,21 +377,21 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b pos = buffer->insert(pos, "\n"); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_1")); #ifdef _WIN32 - auto exampleFilePath = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS"); + const auto exampleFilePath = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_WINDOWS"); #else - auto exampleFilePath = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX"); + const auto exampleFilePath = M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_EXAMPLE_LINUX"); #endif pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", exampleFilePath, "\n")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_PATHS_BODY_2")); // Examples are generated from exampleFilePath using the actual template processing function - Options savedOptions = options; // to be restored after generating example results + const Options savedOptions = options; // to be restored after generating example results options.saveUsePathTemplate = true; // Since this code only ever runs once (the first time the help text is presented), no attempt is // made to be efficient. Use a brute-force method to discover the number of elements in exampleFilePath. int pathElementCount = 0; for (int n=9; n>=0; n--) { - options.savePathTemplate = Glib::ustring::format("%d",n); - auto result = BatchQueue::calcAutoFileNameBase(exampleFilePath); + options.savePathTemplate = Glib::ustring::format("%d", n); + const auto result = BatchQueue::calcAutoFileNameBase(exampleFilePath); if (!result.empty()) { // The 'd' specifier returns an empty string if N exceeds the number of path elements, so // the largest N that does not return an empty string is the number of elements in exampleFilePath. @@ -401,11 +401,11 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b } // Function inserts examples for a particular specifier, with every valid N value for the // number of elements in the path. - auto insertPathExamples = [&buffer, &pos, pathElementCount, exampleFilePath](char letter, int offset1, int mult1, int offset2, int mult2) + const auto insertPathExamples = [&buffer, &pos, pathElementCount, exampleFilePath](char letter, int offset1, int mult1, int offset2, int mult2) { for (int n=0; n b insertPathExamples('p', 1, 1, -pathElementCount, 1); // %p1 = %p-4 = /home/tom/photos/2010-10-31/ insertPathExamples('P', 1, 1, -pathElementCount, 1); // %P1 = %P-4 = 2010-10-31/ { - Glib::ustring fspecifier("%f"); + const Glib::ustring fspecifier("%f"); options.savePathTemplate = fspecifier; - auto result = BatchQueue::calcAutoFileNameBase(exampleFilePath); + const auto result = BatchQueue::calcAutoFileNameBase(exampleFilePath); pos = buffer->insert_markup(pos, Glib::ustring::format("\n ", fspecifier, " = ", result, "")); } @@ -437,15 +437,15 @@ void BatchQueuePanel::populateTemplateHelpBuffer(Glib::RefPtr b insertTopicHeading(M("QUEUE_LOCATION_TEMPLATE_HELP_TIMESTAMP_TITLE")); pos = buffer->insert_markup(pos, M("QUEUE_LOCATION_TEMPLATE_HELP_TIMESTAMP_BODY")); - Glib::ustring dateTimeFormatExamples[] = { + const Glib::ustring dateTimeFormatExamples[] = { "%Y-%m-%d", "%Y%m%d_%H%M%S", "%y/%b/%-d/" }; - auto timezone = Glib::DateTime::create_now_local().get_timezone(); - auto timeForExamples = Glib::DateTime::create_from_iso8601("2001-02-03T04:05:06.123456", timezone); - for (auto fmt : dateTimeFormatExamples) { - auto result = timeForExamples.format(fmt); + const auto timezone = Glib::DateTime::create_now_local().get_timezone(); + const auto timeForExamples = Glib::DateTime::create_from_iso8601("2001-02-03T04:05:06.123456", timezone); + for (auto && fmt : dateTimeFormatExamples) { + const auto result = timeForExamples.format(fmt); pos = buffer->insert_markup(pos, Glib::ustring::format("\n %tE\"", fmt, "\" = ", result, "")); }