[graphics/spectacle] /: Change filename placeholder format

Noah Davis null at kde.org
Fri Dec 1 16:48:25 GMT 2023


Git commit ebee5b1d413eeba6a79f65160bc6cc1e543fdad1 by Noah Davis.
Committed on 01/12/2023 at 17:47.
Pushed by ndavis into branch 'master'.

Change filename placeholder format

Use `<placeholder>` instead of `%placeholder`. This makes it easier to
use
more descriptive or complex placeholders.

Also use more descriptive placeholders since we can and migrate old
placeholders.

With this new format we could add things like `<ISODate>` or
`<ShortDate>` as shorthands for common date/time formats.

I use `<key>` instead of `%key%` because sequences with obvious opening
and closing characters are easier to parse for humans and machines. I
chose '<' and '>' instead of other pairs of characters because I don't
need to escape '<' or '>' in regex. I do need to escape them in Rich
Text/HTML/XML, so it's sometimes less convenient than '{' and '}', but
not too bad.

BUG: 476023

M  +9    -10   doc/index.docbook
M  +7    -0    kconf_update/CMakeLists.txt
A  +70   -0    kconf_update/spectacle-24.02.0-change_placeholder_format.cpp     [License: LGPL(v2.0+)]
M  +4    -0    kconf_update/spectacle.upd
M  +30   -32   src/ExportManager.cpp
M  +13   -1    src/ExportManager.h
M  +3    -0    src/Gui/SettingsDialog/ImageSaveOptions.ui
M  +2    -2    src/Gui/SettingsDialog/ImageSaveOptionsPage.cpp
M  +3    -0    src/Gui/SettingsDialog/VideoSaveOptions.ui
M  +2    -2    src/Gui/SettingsDialog/VideoSaveOptionsPage.cpp
M  +2    -2    src/Gui/SettingsDialog/spectacle.kcfg
M  +21   -22   tests/FilenameTest.cpp

https://invent.kde.org/graphics/spectacle/-/commit/ebee5b1d413eeba6a79f65160bc6cc1e543fdad1

diff --git a/doc/index.docbook b/doc/index.docbook
index 3c28649d3..33d1b5e63 100644
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -366,16 +366,15 @@
                         <para>Set a default filename for saved screenshots.</para>
                         <para>You can use the following placeholders in the filename, which will be replaced with actual text when the file is saved:</para>
                         <itemizedlist>
-                        <listitem><para><userinput>%D</userinput>: Day</para></listitem>
-                        <listitem><para><userinput>%H</userinput>: Hour</para></listitem>
-                        <listitem><para><userinput>%M</userinput>: Month</para></listitem>
-                        <listitem><para><userinput>%Nd</userinput>: Sequential number padded to N digits</para></listitem>
-                        <listitem><para><userinput>%S</userinput>: Second</para></listitem>
-                        <listitem><para><userinput>%T</userinput>: Window title</para></listitem>
-                        <listitem><para><userinput>%Y</userinput>: Year (4 digit)</para></listitem>
-                        <listitem><para><userinput>%Nd</userinput>: Sequential number</para></listitem>
-                        <listitem><para><userinput>%m</userinput>: Minute</para></listitem>
-                        <listitem><para><userinput>%y</userinput>: Year (2 digit)</para></listitem>
+                        <listitem><para><userinput><dd></userinput>: Day</para></listitem>
+                        <listitem><para><userinput><hh></userinput>: Hour</para></listitem>
+                        <listitem><para><userinput><MM></userinput>: Month</para></listitem>
+                        <listitem><para><userinput><ss></userinput>: Second</para></listitem>
+                        <listitem><para><userinput><title></userinput>: Window title</para></listitem>
+                        <listitem><para><userinput><yyyy></userinput>: Year (4 digit)</para></listitem>
+                        <listitem><para><userinput><#></userinput>: Sequential number</para></listitem>
+                        <listitem><para><userinput><mm></userinput>: Minute</para></listitem>
+                        <listitem><para><userinput><yy></userinput>: Year (2 digit)</para></listitem>
                         </itemizedlist>
                         <para>You can click on placeholders in the reference list below to insert them into the <guilabel>Filename</guilabel> line.</para>
                         <para>If a file with this name already exists, a serial number will be appended to the filename. For example, if the filename is <filename>Screenshot</filename>, and <filename>Screenshot.png</filename> already exists, the image will be saved as <filename>Screenshot-1.png</filename>.</para>
diff --git a/kconf_update/CMakeLists.txt b/kconf_update/CMakeLists.txt
index 7deefa118..cb8a9dd8f 100644
--- a/kconf_update/CMakeLists.txt
+++ b/kconf_update/CMakeLists.txt
@@ -26,6 +26,12 @@ target_link_libraries(spectacle-24.02.0-keep_old_filename_templates
     KF6::XmlGui
 )
 
+add_executable(spectacle-24.02.0-change_placeholder_format "spectacle-24.02.0-change_placeholder_format.cpp")
+target_link_libraries(spectacle-24.02.0-change_placeholder_format
+    KF6::ConfigCore
+    KF6::XmlGui
+)
+
 # install C++ scripts to kconf_update_bin
 install(
     TARGETS
@@ -33,5 +39,6 @@ install(
         spectacle-24.02.0-keep_old_save_location
         spectacle-24.02.0-rename_settings
         spectacle-24.02.0-keep_old_filename_templates
+        spectacle-24.02.0-change_placeholder_format
     DESTINATION ${KDE_INSTALL_LIBDIR}/kconf_update_bin
 )
diff --git a/kconf_update/spectacle-24.02.0-change_placeholder_format.cpp b/kconf_update/spectacle-24.02.0-change_placeholder_format.cpp
new file mode 100644
index 000000000..f8f722e12
--- /dev/null
+++ b/kconf_update/spectacle-24.02.0-change_placeholder_format.cpp
@@ -0,0 +1,70 @@
+/* SPDX-FileCopyrightText: 2023 Noah Davis <noahadvs at gmail.com>
+ * SPDX-License-Identifier: LGPL-2.0-or-later
+ */
+
+#include "ConfigUtils.h"
+#include <KConfigGroup>
+#include <KSharedConfig>
+#include <QRegularExpression>
+
+using namespace Qt::StringLiterals;
+
+const ValueMap oldNewMap{
+    {u"%Y"_s, u"<yyyy>"_s},
+    {u"%y"_s, u"<yy>"_s},
+    {u"%M"_s, u"<MM>"_s},
+    {u"%n"_s, u"<MMM>"_s},
+    {u"%N"_s, u"<MMMM>"_s},
+    {u"%D"_s, u"<dd>"_s},
+    {u"%H"_s, u"<hh>"_s},
+    {u"%m"_s, u"<mm>"_s},
+    {u"%S"_s, u"<ss>"_s},
+    {u"%t"_s, u"<t>"_s},
+    {u"%T"_s, u"<title>"_s},
+};
+
+inline QString changedFormat(QString filenameTemplate)
+{
+    for (auto it = oldNewMap.cbegin(); it != oldNewMap.cend(); ++it) {
+        filenameTemplate.replace(it.key(), it.value());
+    }
+
+    QRegularExpression sequenceRE(u"%(\\d*)d"_s);
+    auto it = sequenceRE.globalMatch(filenameTemplate);
+    while (it.hasNext()) {
+        auto match = it.next();
+        int padding = 0;
+        if (!match.captured(1).isEmpty()) {
+            padding = match.captured(1).toInt();
+        }
+        auto newValue = u"<%1>"_s.arg(u"#"_s, padding, u'#');
+        filenameTemplate.replace(match.captured(), newValue);
+    }
+
+    return filenameTemplate;
+}
+
+int main()
+{
+    const auto fileName = u"spectaclerc"_s;
+    if (!continueUpdate(fileName, u"2024-02-28T00:00:00Z"_s)) {
+        return 0;
+    }
+
+    // We only need to read spectaclerc, so we use SimpleConfig.
+    auto spectaclerc = KSharedConfig::openConfig(fileName, KConfig::SimpleConfig);
+
+    auto imageSaveGroup = spectaclerc->group(QStringLiteral("ImageSave"));
+    if (!isEntryDefault(imageSaveGroup, "imageFilenameTemplate")) {
+        auto value = imageSaveGroup.readEntry("imageFilenameTemplate");
+        imageSaveGroup.writeEntry("imageFilenameTemplate", changedFormat(value));
+    }
+
+    auto videoSaveGroup = spectaclerc->group(QStringLiteral("VideoSave"));
+    if (!isEntryDefault(videoSaveGroup, "videoFilenameTemplate")) {
+        auto value = videoSaveGroup.readEntry("videoFilenameTemplate");
+        videoSaveGroup.writeEntry("videoFilenameTemplate", changedFormat(value));
+    }
+
+    return spectaclerc->sync() ? 0 : 1;
+}
diff --git a/kconf_update/spectacle.upd b/kconf_update/spectacle.upd
index f2f2a362a..6659b2110 100644
--- a/kconf_update/spectacle.upd
+++ b/kconf_update/spectacle.upd
@@ -42,3 +42,7 @@ Script=spectacle-24.02.0-rename_settings
 # Keep old default image and video filename templates for users with existing configs
 Id=24.02.0-keep_old_filename_templates
 Script=spectacle-24.02.0-keep_old_filename_templates
+
+# Change filename placeholders to new format
+Id=24.02.0-change_placeholder_format
+Script=spectacle-24.02.0-change_placeholder_format
diff --git a/src/ExportManager.cpp b/src/ExportManager.cpp
index 7eecdb340..dca509bf2 100644
--- a/src/ExportManager.cpp
+++ b/src/ExportManager.cpp
@@ -197,28 +197,28 @@ QString ExportManager::formattedFilename(const QString &nameTemplate) const
     if (!title.isEmpty()) {
         title.replace(u'/', u'_'); // POSIX doesn't allow "/" in filenames
     } else {
-        // Remove '%T' with separators around it
+        // Remove <title> with separators around it
         const auto wordSymbol = uR"(\p{L}\p{M}\p{N})"_s;
         const auto separator = u"([^%1]+)"_s.arg(wordSymbol);
-        const auto re = QRegularExpression(u"(.*?)(%1%T|%T%1)(.*?)"_s.arg(separator));
+        const auto re = QRegularExpression(u"(.*?)(%1<title>|<title>%1)(.*?)"_s.arg(separator));
         baseName.replace(re, uR"(\1\5)"_s);
     }
 
-    QString result = baseName.replace("%Y"_L1, timestamp.toString(u"yyyy"_s))
-                             .replace("%y"_L1, timestamp.toString(u"yy"_s))
-                             .replace("%M"_L1, timestamp.toString(u"MM"_s))
-                             .replace("%n"_L1, timestamp.toString(u"MMM"_s))
-                             .replace("%N"_L1, timestamp.toString(u"MMMM"_s))
-                             .replace("%D"_L1, timestamp.toString(u"dd"_s))
-                             .replace("%H"_L1, timestamp.toString(u"hh"_s))
-                             .replace("%m"_L1, timestamp.toString(u"mm"_s))
-                             .replace("%S"_L1, timestamp.toString(u"ss"_s))
-                             .replace("%t"_L1, timestamp.toString(u"t"_s))
-                             .replace("%T"_L1, title);
+    QString result = baseName.replace("<yyyy>"_L1, timestamp.toString(u"yyyy"_s))
+                             .replace("<yy>"_L1, timestamp.toString(u"yy"_s))
+                             .replace("<MM>"_L1, timestamp.toString(u"MM"_s))
+                             .replace("<MMM>"_L1, timestamp.toString(u"MMM"_s))
+                             .replace("<MMMM>"_L1, timestamp.toString(u"MMMM"_s))
+                             .replace("<dd>"_L1, timestamp.toString(u"dd"_s))
+                             .replace("<hh>"_L1, timestamp.toString(u"hh"_s))
+                             .replace("<mm>"_L1, timestamp.toString(u"mm"_s))
+                             .replace("<ss>"_L1, timestamp.toString(u"ss"_s))
+                             .replace("<t>"_L1, timestamp.toString(u"t"_s))
+                             .replace("<title>"_L1, title);
 
     // check if basename includes %[N]d token for sequential file numbering
     QRegularExpression paddingRE;
-    paddingRE.setPattern(u"%(\\d*)d"_s);
+    paddingRE.setPattern(u"<(#+)>"_s);
     QRegularExpressionMatchIterator it = paddingRE.globalMatch(result);
     if (it.hasNext()) {
         // strip any subdirectories from the template to construct the filename matching regex
@@ -231,7 +231,7 @@ QString ExportManager::formattedFilename(const QString &nameTemplate) const
             // determine padding value
             int paddedLength = 1;
             if (!paddingMatch.captured(1).isEmpty()) {
-                paddedLength = paddingMatch.captured(1).toInt();
+                paddedLength = paddingMatch.captured(1).length();
             }
             QString escapedMatch = QRegularExpression::escape(paddingMatch.captured());
             resultCopy.replace(escapedMatch, u"(\\d{%1,})"_s.arg(QString::number(paddedLength)));
@@ -257,7 +257,7 @@ QString ExportManager::formattedFilename(const QString &nameTemplate) const
             if (filteredFiles.length() > 0) {
                 // loop through filtered file names looking for highest number
                 for (const QString &filteredFile : filteredFiles) {
-                    int currentFileNumber = fileNumberRE.match(filteredFile).captured(1).toInt();
+                    int currentFileNumber = fileNumberRE.match(filteredFile).captured(1).length();
                     if (currentFileNumber > highestFileNumber) {
                         highestFileNumber = currentFileNumber;
                     }
@@ -268,7 +268,7 @@ QString ExportManager::formattedFilename(const QString &nameTemplate) const
         for (const auto &match : matches) {
             int paddedLength = 1;
             if (!match.captured(1).isEmpty()) {
-                paddedLength = match.captured(1).toInt();
+                paddedLength = match.captured(1).length();
             }
             const QString nextFileNumberPadded = QString::number(highestFileNumber + 1).rightJustified(paddedLength, u'0');
             result.replace(match.captured(), nextFileNumberPadded);
@@ -735,21 +735,19 @@ void ExportManager::doPrint(QPrinter *printer)
     painter.end();
 }
 
-const QMap<QString, KLocalizedString> ExportManager::filenamePlaceholders{
-    {u"%Y"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Year (4 digit)")},
-    {u"%y"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Year (2 digit)")},
-    {u"%M"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Month")},
-    {u"%n"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Month (localized short name)")},
-    {u"%N"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Month (localized long name)")},
-    {u"%D"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Day")},
-    {u"%H"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Hour")},
-    {u"%m"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Minute")},
-    {u"%S"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Second")},
-    {u"%t"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Timezone")},
-    {u"%T"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Window Title")},
-    {u"%d"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Sequential numbering")},
-    {u"%Nd"_s,
-     ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Sequential numbering, padded out to N digits")},
+const QList<ExportManager::Placeholder> ExportManager::filenamePlaceholders{
+    {u"yyyy"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Year (4 digit)")},
+    {u"yy"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Year (2 digit)")},
+    {u"MM"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Month")},
+    {u"MMM"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Month (localized short name)")},
+    {u"MMMM"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Month (localized long name)")},
+    {u"dd"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Day")},
+    {u"hh"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Hour")},
+    {u"mm"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Minute")},
+    {u"ss"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Second")},
+    {u"t"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Timezone")},
+    {u"title"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Window Title")},
+    {u"#"_s, ki18nc("A placeholder in the user configurable filename will replaced by the specified value", "Sequential numbering, padded by inserting additional '#' characters")},
 };
 
 #include "moc_ExportManager.cpp"
diff --git a/src/ExportManager.h b/src/ExportManager.h
index 6bc2a8463..0f25961ab 100644
--- a/src/ExportManager.h
+++ b/src/ExportManager.h
@@ -74,7 +74,19 @@ public:
 
     const QTemporaryDir *temporaryDir();
 
-    static const QMap<QString, KLocalizedString> filenamePlaceholders;
+    struct Placeholder {
+        // Expect the config UI to use rich text.
+        const QString htmlKey;
+        const KLocalizedString description;
+
+        Placeholder(const QString &key, const KLocalizedString &description)
+            : htmlKey(u"<" % key % u">") // key -> <key> in HTML
+            , description(description)
+        {
+        }
+    };
+
+    static const QList<Placeholder> filenamePlaceholders;
 
 Q_SIGNALS:
     void imageChanged();
diff --git a/src/Gui/SettingsDialog/ImageSaveOptions.ui b/src/Gui/SettingsDialog/ImageSaveOptions.ui
index 3a6b161f0..a130f3264 100644
--- a/src/Gui/SettingsDialog/ImageSaveOptions.ui
+++ b/src/Gui/SettingsDialog/ImageSaveOptions.ui
@@ -146,6 +146,9 @@
      <property name="text">
       <string/>
      </property>
+     <property name="textFormat">
+      <enum>Qt::RichText</enum>
+     </property>
      <property name="wordWrap">
       <bool>true</bool>
      </property>
diff --git a/src/Gui/SettingsDialog/ImageSaveOptionsPage.cpp b/src/Gui/SettingsDialog/ImageSaveOptionsPage.cpp
index fca12edc3..4f806215b 100644
--- a/src/Gui/SettingsDialog/ImageSaveOptionsPage.cpp
+++ b/src/Gui/SettingsDialog/ImageSaveOptionsPage.cpp
@@ -57,8 +57,8 @@ ImageSaveOptionsPage::ImageSaveOptionsPage(QWidget *parent)
     QString captureInstruction = i18n(
         "You can use the following placeholders in the filename, which will be replaced "
         "with actual text when the file is saved:<blockquote>");
-    for (auto option = ExportManager::filenamePlaceholders.cbegin(); option != ExportManager::filenamePlaceholders.cend(); ++option) {
-        captureInstruction += u"<a href=%1>%1</a>: %2<br>"_s.arg(option.key(), option.value().toString());
+    for (auto it = ExportManager::filenamePlaceholders.cbegin(); it != ExportManager::filenamePlaceholders.cend(); ++it) {
+        captureInstruction += u"<a href=%1>%1</a>: %2<br>"_s.arg(it->htmlKey, it->description.toString());
     }
     captureInstruction += u"<a href='/'>/</a>: "_s + i18n("To save to a sub-folder");
     captureInstruction += u"</blockquote>"_s;
diff --git a/src/Gui/SettingsDialog/VideoSaveOptions.ui b/src/Gui/SettingsDialog/VideoSaveOptions.ui
index 4469e8f99..8f64ecef2 100644
--- a/src/Gui/SettingsDialog/VideoSaveOptions.ui
+++ b/src/Gui/SettingsDialog/VideoSaveOptions.ui
@@ -103,6 +103,9 @@
      <property name="text">
       <string/>
      </property>
+     <property name="textFormat">
+      <enum>Qt::RichText</enum>
+     </property>
      <property name="wordWrap">
       <bool>true</bool>
      </property>
diff --git a/src/Gui/SettingsDialog/VideoSaveOptionsPage.cpp b/src/Gui/SettingsDialog/VideoSaveOptionsPage.cpp
index cf08fc923..63354a814 100644
--- a/src/Gui/SettingsDialog/VideoSaveOptionsPage.cpp
+++ b/src/Gui/SettingsDialog/VideoSaveOptionsPage.cpp
@@ -60,8 +60,8 @@ VideoSaveOptionsPage::VideoSaveOptionsPage(QWidget *parent)
     QString captureInstruction = i18n(
         "You can use the following placeholders in the filename, which will be replaced "
         "with actual text when the file is saved:<blockquote>");
-    for (auto option = ExportManager::filenamePlaceholders.cbegin(); option != ExportManager::filenamePlaceholders.cend(); ++option) {
-        captureInstruction += u"<a href=%1>%1</a>: %2<br>"_s.arg(option.key(), option.value().toString());
+    for (auto it = ExportManager::filenamePlaceholders.cbegin(); it != ExportManager::filenamePlaceholders.cend(); ++it) {
+        captureInstruction += u"<a href=%1>%1</a>: %2<br>"_s.arg(it->htmlKey, it->description.toString());
     }
     captureInstruction += u"<a href='/'>/</a>: "_s + i18n("To save to a sub-folder");
     captureInstruction += u"</blockquote>"_s;
diff --git a/src/Gui/SettingsDialog/spectacle.kcfg b/src/Gui/SettingsDialog/spectacle.kcfg
index 1a81dc855..2d3705d39 100644
--- a/src/Gui/SettingsDialog/spectacle.kcfg
+++ b/src/Gui/SettingsDialog/spectacle.kcfg
@@ -146,7 +146,7 @@
         <label>The filename template used when saving screenshots</label>
         <default code="true">
             i18nc("part of default image filename template", "Screenshot")
-            + u"_%Y%M%D_%H%m%S"
+            + u"_<yyyy><MM><dd>_<hh><mm><ss>"
         </default>
     </entry>
     <entry name="lastImageSaveLocation" type="Url">
@@ -185,7 +185,7 @@
         <label>The filename template used when saving screencasts</label>
         <default code="true">
             i18nc("part of default video filename template", "Screencast")
-            + u"_%Y%M%D_%H%m%S"
+            + u"_<yyyy><MM><dd>_<hh><mm><ss>"
         </default>
     </entry>
     <entry name="lastVideoSaveLocation" type="Url">
diff --git a/tests/FilenameTest.cpp b/tests/FilenameTest.cpp
index 030d4b1a1..83215522e 100644
--- a/tests/FilenameTest.cpp
+++ b/tests/FilenameTest.cpp
@@ -48,56 +48,55 @@ void FilenameTest::testStrings()
 
 void FilenameTest::testDateTokens()
 {
-    QCOMPARE(mExportManager->formattedFilename(u"%Y"_s), u"2019"_s);
-    QCOMPARE(mExportManager->formattedFilename(u"%y"_s), u"19"_s);
-    QCOMPARE(mExportManager->formattedFilename(u"%M"_s), u"03"_s);
-    QCOMPARE(mExportManager->formattedFilename(u"%D"_s), u"22"_s);
-    QCOMPARE(mExportManager->formattedFilename(u"%H"_s), u"10"_s);
-    QCOMPARE(mExportManager->formattedFilename(u"%m"_s), u"43"_s);
-    QCOMPARE(mExportManager->formattedFilename(u"%S"_s), u"25"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"<yyyy>"_s), u"2019"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"<yy>"_s), u"19"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"<MM>"_s), u"03"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"<dd>"_s), u"22"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"<hh>"_s), u"10"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"<mm>"_s), u"43"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"<ss>"_s), u"25"_s);
 }
 
 void FilenameTest::testWindowTitle()
 {
     mExportManager->setWindowTitle(u"Spectacle"_s);
-    QCOMPARE(mExportManager->formattedFilename(u"%T"_s), u"Spectacle"_s);
-    QCOMPARE(mExportManager->formattedFilename(u"Before%TAfter"_s), u"BeforeSpectacleAfter"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"<title>"_s), u"Spectacle"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"Before<title>After"_s), u"BeforeSpectacleAfter"_s);
     mExportManager->setWindowTitle({});
     // Empty String produces Screenshot
-    QCOMPARE(mExportManager->formattedFilename(u"%T"_s), u"Screenshot"_s);
-    QCOMPARE(mExportManager->formattedFilename(u"Before%TAfter"_s), u"BeforeAfter"_s);
-    QCOMPARE(mExportManager->formattedFilename(u"Before_%T_After"_s), u"Before_After"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"<title>"_s), u"Screenshot"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"Before<title>After"_s), u"BeforeAfter"_s);
+    QCOMPARE(mExportManager->formattedFilename(u"Before_<title>_After"_s), u"Before_After"_s);
 }
 
 void FilenameTest::testNumbering()
 {
     QString BaseName = u"spectacle_test_" + QUuid::createUuid().toString();
-    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_%d"_s), BaseName + u"_1"_s);
-    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_%1d"_s), BaseName + u"_1"_s);
-    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_%2d"_s), BaseName + u"_01"_s);
-    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_%3d"_s), BaseName + u"_001"_s);
-    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_%4d"_s), BaseName + u"_0001"_s);
-    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_%d_%2d_%3d"_s), BaseName + u"_1_01_001"_s);
+    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_<#>"_s), BaseName + u"_1"_s);
+    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_<##>"_s), BaseName + u"_01"_s);
+    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_<###>"_s), BaseName + u"_001"_s);
+    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_<####>"_s), BaseName + u"_0001"_s);
+    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_<#>_<##>_<###>"_s), BaseName + u"_1_01_001"_s);
 
     QFile file(QDir(mExportManager->defaultSaveLocation()).filePath(BaseName + u"_1.png"_s));
     file.open(QIODevice::WriteOnly);
     file.close();
-    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_%d"_s), BaseName + u"_2"_s);
+    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_<#>"_s), BaseName + u"_2"_s);
     file.remove();
     file.setFileName(QDir(mExportManager->defaultSaveLocation()).filePath(BaseName + u"_1_01_001"_s));
     file.open(QIODevice::WriteOnly);
     file.close();
-    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_%d_%2d_%3d"_s), BaseName + u"_2_02_002"_s);
+    QCOMPARE(mExportManager->formattedFilename(BaseName + u"_<#>_<##>_<###>"_s), BaseName + u"_2_02_002"_s);
     file.remove();
 }
 
 void FilenameTest::testCombined()
 {
     mExportManager->setWindowTitle(u"Spectacle"_s);
-    QCOMPARE(mExportManager->formattedFilename(u"App_%T_Date_%Y%M%D_Time_%H:%m:%S%F"_s),
+    QCOMPARE(mExportManager->formattedFilename(u"App_<title>_Date_<yyyy><MM><dd>_Time_<hh>:<mm>:<ss>%F"_s),
              u"App_Spectacle_Date_20190322_Time_10:43:25%F"_s);
     mExportManager->setWindowTitle({});
-    QCOMPARE(mExportManager->formattedFilename(u"App_%T_Date_%Y%M%D_Time_%H:%m:%S%F"_s),
+    QCOMPARE(mExportManager->formattedFilename(u"App_<title>_Date_<yyyy><MM><dd>_Time_<hh>:<mm>:<ss>%F"_s),
              u"App_Date_20190322_Time_10:43:25%F"_s);
 }
 


More information about the kde-doc-english mailing list