File indexing completed on 2025-02-09 05:17:56

0001 /* SPDX-FileCopyrightText: 2023 Noah Davis <noahadvs@gmail.com>
0002  * SPDX-License-Identifier: LGPL-2.0-or-later
0003  */
0004 
0005 #pragma once
0006 
0007 #include "ExportManager.h"
0008 
0009 #include <KLocalizedString>
0010 
0011 #include <QApplication>
0012 #include <QFontDatabase>
0013 #include <QGuiApplication>
0014 #include <QLabel>
0015 #include <QStyle>
0016 
0017 using namespace Qt::StringLiterals;
0018 
0019 /**
0020  * A small collection of functions to help prevent duplicating the implementations of the
0021  * image and video save options pages.
0022  */
0023 
0024 inline void updateFilenamePreview(QLabel *label, const QString &templateFilename)
0025 {
0026     auto exportManager = ExportManager::instance();
0027     // If there is no window title, we need to change it to have a placeholder.
0028     const bool usePlaceholder = exportManager->windowTitle().isEmpty();
0029     if (usePlaceholder) {
0030         exportManager->setWindowTitle(QGuiApplication::applicationDisplayName());
0031     }
0032     // Likewise, if no timestamp was set yet, we'll produce a new one as placeholder.
0033     const QDateTime timestamp = exportManager->timestamp();
0034     if (!timestamp.isValid()) {
0035         exportManager->updateTimestamp();
0036     }
0037     const auto filename = exportManager->formattedFilename(templateFilename);
0038     label->setText(xi18nc("@info", "<filename>%1</filename>", filename));
0039 
0040     // Reset any previously empty values that we had temporarily set.
0041     if (!timestamp.isValid()) {
0042         exportManager->setTimestamp(timestamp);
0043     }
0044     if (usePlaceholder) {
0045         exportManager->setWindowTitle({});
0046     }
0047 }
0048 
0049 namespace CaptureInstructionHelpers
0050 {
0051 inline QString tableRow(const QString &href, const QString &label, const QString &description = {})
0052 {
0053     QString cell1 = u"<a href='%1'><code>%2</code></a>"_s.arg(href, label);
0054     // clang-format off
0055     return uR"(
0056             <tr><td>%1</td>
0057                 <td>%2</td></tr>)"_s.arg(cell1, description);
0058     // clang-format on
0059 }
0060 inline QString buttonRow(const QString &href, const QString &label)
0061 {
0062     QString cell2 = u"<a href='%1'>%2</a>"_s.arg(href, label);
0063     // clang-format off
0064     return uR"(
0065             <tr><td>&nbsp;</td>
0066                 <td>%1</td></tr>)"_s.arg(cell2);
0067     // clang-format on
0068 }
0069 }
0070 
0071 inline QString captureInstructions(bool showExtras)
0072 {
0073     using namespace CaptureInstructionHelpers;
0074     QString intro = i18n("You can use the following placeholders in the filename, which will be replaced with actual text when the file is saved:");
0075 
0076     QString tableBody;
0077     bool hasAnyExtras = false;
0078     for (auto it = ExportManager::filenamePlaceholders.cbegin(); it != ExportManager::filenamePlaceholders.cend(); ++it) {
0079         using Flag = ExportManager::Placeholder::Flag;
0080         if (it->flags.testFlag(Flag::Hidden)) {
0081             continue;
0082         }
0083         const bool isExtra = it->flags.testFlag(Flag::Extra);
0084         hasAnyExtras |= isExtra;
0085         if (showExtras || !isExtra) {
0086             tableBody += tableRow(it->plainKey, it->htmlKey, it->description.toString());
0087         }
0088     }
0089     tableBody += tableRow(u"/"_s, u"/"_s, i18n("To save to a sub-folder"));
0090     if (hasAnyExtras) {
0091         if (showExtras) {
0092             tableBody += buttonRow(u"showfewer"_s, i18nc("show fewer filename placeholder templates", "Show Fewer"));
0093         } else {
0094             tableBody += buttonRow(u"showmore"_s, i18nc("show more filename placeholder templates", "Show More"));
0095         }
0096     }
0097 
0098     auto hspacing = qApp->style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
0099     // Make the distance from the bottom of a typical capital letter to the top of another below it
0100     // equal to QLayout vertical spacing, unless it is less than the largest descent.
0101     qreal vspacing = qApp->style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing);
0102     QFontMetricsF generalMetrics(QFontDatabase::systemFont(QFontDatabase::GeneralFont));
0103     QFontMetricsF fixedMetrics(QFontDatabase::systemFont(QFontDatabase::FixedFont));
0104     vspacing = std::max(0.0, vspacing - std::max(generalMetrics.descent(), fixedMetrics.descent()));
0105 
0106     static const QString html = // clang-format off
0107     // We simulate independent vertical and horizontal cell spacing by using padding for cells
0108     // and negative margins for the table.
0109 uR"(<html>
0110     <head>
0111         <style>
0112             table {
0113                 border: 0px none transparent;
0114                 margin-left: -%1px;
0115                 margin-right: -%1px;
0116                 margin-top: -%2px;
0117                 margin-bottom: -%2px;
0118             }
0119             td {
0120                 border: 0px none transparent;
0121                 padding-left: %1px;
0122                 padding-right: %1px;
0123                 padding-top: %2px;
0124                 padding-bottom: %2px;
0125             }
0126         </style>
0127     </head>
0128     <body>
0129         <p>%3</p>
0130         <p><table cellspacing='0' cellpadding='0'>%4
0131         </table></p>
0132     </body>
0133 </html>)"_s; // clang-format on
0134     return html.arg(QString::number(hspacing), QString::number(vspacing / 2.0), intro, tableBody);
0135 }