File indexing completed on 2024-04-28 04:21:05

0001 // SPDX-FileCopyrightText: 2003-2020 The KPhotoAlbum Development Team
0002 // SPDX-FileCopyrightText: 2022-2023 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
0003 //
0004 // SPDX-License-Identifier: GPL-2.0-or-later
0005 
0006 #include "HTMLDialog.h"
0007 
0008 #include "Generator.h"
0009 #include "ImageSizeCheckBox.h"
0010 #include "Logging.h"
0011 
0012 #include <DB/CategoryCollection.h>
0013 #include <DB/ImageDB.h>
0014 #include <MainWindow/Window.h>
0015 #include <kpabase/SettingsData.h>
0016 
0017 #include <KColorScheme>
0018 #include <KConfig>
0019 #include <KConfigGroup>
0020 #include <KFileItem>
0021 #include <KIO/DeleteJob>
0022 #include <KIO/StatJob>
0023 #include <KJob>
0024 #include <KJobWidgets>
0025 #include <KLocalizedString>
0026 #include <KMessageBox>
0027 #include <KTextEdit>
0028 #include <QCheckBox>
0029 #include <QComboBox>
0030 #include <QDialogButtonBox>
0031 #include <QFileDialog>
0032 #include <QGroupBox>
0033 #include <QHBoxLayout>
0034 #include <QLabel>
0035 #include <QLayout>
0036 #include <QLineEdit>
0037 #include <QPushButton>
0038 #include <QScopedPointer>
0039 #include <QSpinBox>
0040 #include <QStandardPaths>
0041 #include <QStringMatcher>
0042 #include <QVBoxLayout>
0043 #include <kio_version.h>
0044 #include <kwidgetsaddons_version.h>
0045 
0046 using namespace HTMLGenerator;
0047 
0048 HTMLDialog::HTMLDialog(QWidget *parent)
0049     : KPageDialog(parent)
0050     , m_list()
0051 {
0052     setWindowTitle(i18nc("@title:window", "HTML Export"));
0053     QWidget *mainWidget = new QWidget(this);
0054     this->layout()->addWidget(mainWidget);
0055 
0056     createContentPage();
0057     createLayoutPage();
0058     createDestinationPage();
0059     // destUrl is only relevant for .kim file creation:
0060     connect(m_generateKimFile, &QCheckBox::toggled, m_destURL, &QLineEdit::setEnabled);
0061     // automatically fill in output directory:
0062     connect(m_title, &QLineEdit::editingFinished, this, &HTMLDialog::slotSuggestOutputDir);
0063 
0064     QDialogButtonBox *buttonBox = this->buttonBox();
0065     connect(buttonBox, &QDialogButtonBox::accepted, this, &HTMLDialog::accept);
0066     connect(buttonBox, &QDialogButtonBox::rejected, this, &HTMLDialog::reject);
0067     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0068     okButton->setDefault(true);
0069     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0070     okButton->setEnabled(m_themes.size() > 0);
0071     connect(okButton, &QPushButton::clicked, this, &HTMLDialog::slotOk);
0072     this->layout()->addWidget(buttonBox);
0073 }
0074 
0075 void HTMLDialog::createContentPage()
0076 {
0077     QWidget *contentPage = new QWidget;
0078     KPageWidgetItem *page = new KPageWidgetItem(contentPage, i18n("Content"));
0079     page->setHeader(i18n("Content"));
0080     page->setIcon(QIcon::fromTheme(QString::fromLatin1("document-properties")));
0081     addPage(page);
0082 
0083     QVBoxLayout *lay1 = new QVBoxLayout(contentPage);
0084     QGridLayout *lay2 = new QGridLayout;
0085     lay1->addLayout(lay2);
0086 
0087     QLabel *label = new QLabel(i18n("Page title:"), contentPage);
0088     lay2->addWidget(label, 0, 0);
0089     m_title = new QLineEdit(contentPage);
0090     label->setBuddy(m_title);
0091     lay2->addWidget(m_title, 0, 1);
0092 
0093     // Copyright
0094     label = new QLabel(i18n("Copyright:"), contentPage);
0095     label->setAlignment(Qt::AlignTop);
0096     lay2->addWidget(label, 1, 0);
0097     m_copyright = new QLineEdit(contentPage);
0098     m_copyright->setText(Settings::SettingsData::instance()->HTMLCopyright());
0099     label->setBuddy(m_copyright);
0100     lay2->addWidget(m_copyright, 1, 1);
0101 
0102     // Description
0103     label = new QLabel(i18n("Description:"), contentPage);
0104     label->setAlignment(Qt::AlignTop);
0105     lay2->addWidget(label, 2, 0);
0106     m_description = new KTextEdit(contentPage);
0107     label->setBuddy(m_description);
0108     lay2->addWidget(m_description, 2, 1);
0109 
0110     m_generateKimFile = new QCheckBox(i18n("Create .kim export file"), contentPage);
0111     m_generateKimFile->setChecked(Settings::SettingsData::instance()->HTMLKimFile());
0112     lay1->addWidget(m_generateKimFile);
0113 
0114     m_inlineMovies = new QCheckBox(i18nc("Inline as a verb, i.e. 'please show movies right on the page, not as links'",
0115                                          "Inline Movies in pages"),
0116                                    contentPage);
0117     m_inlineMovies->setChecked(Settings::SettingsData::instance()->HTMLInlineMovies());
0118     lay1->addWidget(m_inlineMovies);
0119 
0120     m_html5Video = new QCheckBox(i18nc("Tag as in HTML-tag, not as in image tag", "Use HTML5 video tag"), contentPage);
0121     m_html5Video->setChecked(Settings::SettingsData::instance()->HTML5Video());
0122     lay1->addWidget(m_html5Video);
0123 
0124     QString avconv = QStandardPaths::findExecutable(QString::fromUtf8("avconv"));
0125     if (avconv.isNull())
0126         avconv = QStandardPaths::findExecutable(QString::fromUtf8("ffmpeg"));
0127     const QString ffmpeg2theora = QStandardPaths::findExecutable(QString::fromUtf8("ffmpeg2theora"));
0128 
0129     QString txt = i18n("<p>This selection will generate video files suitable for displaying on web. "
0130                        "avconv and ffmpeg2theora are required for video file generation.</p>");
0131     m_html5VideoGenerate = new QCheckBox(i18n("Generate HTML5 video files (mp4 and ogg)"), contentPage);
0132     m_html5VideoGenerate->setChecked(Settings::SettingsData::instance()->HTML5VideoGenerate());
0133     lay1->addWidget(m_html5VideoGenerate);
0134     m_html5VideoGenerate->setWhatsThis(txt);
0135     if (avconv.isNull() || ffmpeg2theora.isNull())
0136         m_html5VideoGenerate->setEnabled(false);
0137 
0138     // What to include
0139     QGroupBox *whatToInclude = new QGroupBox(i18n("What to Include"), contentPage);
0140     lay1->addWidget(whatToInclude);
0141     QGridLayout *lay3 = new QGridLayout(whatToInclude);
0142 
0143     QCheckBox *cb = new QCheckBox(i18n("Description"), whatToInclude);
0144     m_whatToIncludeMap.insert(QString::fromLatin1("**DESCRIPTION**"), cb);
0145     lay3->addWidget(cb, 0, 0);
0146 
0147     m_date = new QCheckBox(i18n("Date"), whatToInclude);
0148     m_date->setChecked(Settings::SettingsData::instance()->HTMLDate());
0149     m_whatToIncludeMap.insert(QString::fromLatin1("**DATE**"), m_date);
0150     lay3->addWidget(m_date, 0, 1);
0151 
0152     int row = 1;
0153     int col = 0;
0154     QString selectionsTmp = Settings::SettingsData::instance()->HTMLIncludeSelections();
0155     QStringMatcher *pattern = new QStringMatcher();
0156     pattern->setPattern(QString::fromLatin1("**DESCRIPTION**"));
0157     cb->setChecked(pattern->indexIn(selectionsTmp) >= 0 ? 1 : 0);
0158 
0159     QList<DB::CategoryPtr> categories = DB::ImageDB::instance()->categoryCollection()->categories();
0160     for (QList<DB::CategoryPtr>::Iterator it = categories.begin(); it != categories.end(); ++it) {
0161         if (!(*it)->isSpecialCategory()) {
0162             QCheckBox *cb = new QCheckBox((*it)->name(), whatToInclude);
0163             lay3->addWidget(cb, row, col % 2);
0164             m_whatToIncludeMap.insert((*it)->name(), cb);
0165             pattern->setPattern((*it)->name());
0166             cb->setChecked(pattern->indexIn(selectionsTmp) >= 0 ? 1 : 0);
0167             if (++col % 2 == 0)
0168                 ++row;
0169         }
0170     }
0171 }
0172 
0173 void HTMLDialog::createLayoutPage()
0174 {
0175     QWidget *layoutPage = new QWidget;
0176     KPageWidgetItem *page = new KPageWidgetItem(layoutPage, i18n("Layout"));
0177     page->setHeader(i18n("Layout"));
0178     page->setIcon(QIcon::fromTheme(QString::fromLatin1("configure")));
0179     addPage(page);
0180 
0181     QVBoxLayout *lay1 = new QVBoxLayout(layoutPage);
0182     QGridLayout *lay2 = new QGridLayout;
0183     lay1->addLayout(lay2);
0184 
0185     // Thumbnail size
0186     QLabel *label = new QLabel(i18n("Thumbnail size:"), layoutPage);
0187     lay2->addWidget(label, 0, 0);
0188 
0189     QHBoxLayout *lay3 = new QHBoxLayout;
0190     lay2->addLayout(lay3, 0, 1);
0191 
0192     m_thumbSize = new QSpinBox;
0193     m_thumbSize->setRange(16, 256);
0194 
0195     m_thumbSize->setValue(Settings::SettingsData::instance()->HTMLThumbSize());
0196     lay3->addWidget(m_thumbSize);
0197     lay3->addStretch(1);
0198     label->setBuddy(m_thumbSize);
0199 
0200     // Number of columns
0201     label = new QLabel(i18n("Number of columns:"), layoutPage);
0202     lay2->addWidget(label, 1, 0);
0203 
0204     QHBoxLayout *lay4 = new QHBoxLayout;
0205     lay2->addLayout(lay4, 1, 1);
0206     m_numOfCols = new QSpinBox;
0207     m_numOfCols->setRange(1, 10);
0208 
0209     label->setBuddy(m_numOfCols);
0210 
0211     m_numOfCols->setValue(Settings::SettingsData::instance()->HTMLNumOfCols());
0212     lay4->addWidget(m_numOfCols);
0213     lay4->addStretch(1);
0214 
0215     // Theme box
0216     label = new QLabel(i18n("Theme:"), layoutPage);
0217     lay2->addWidget(label, 2, 0);
0218     lay4 = new QHBoxLayout;
0219     lay2->addLayout(lay4, 2, 1);
0220     m_themeBox = new KComboBox(layoutPage);
0221     label->setBuddy(m_themeBox);
0222     lay4->addWidget(m_themeBox);
0223     lay4->addStretch(1);
0224     m_themeInfo = new QLabel(i18n("Theme Description"), layoutPage);
0225     m_themeInfo->setWordWrap(true);
0226     lay2->addWidget(m_themeInfo, 3, 1);
0227     connect(m_themeBox, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this, &HTMLDialog::displayThemeDescription);
0228     populateThemesCombo();
0229 
0230     // Image sizes
0231     QGroupBox *sizes = new QGroupBox(i18n("Image Sizes"), layoutPage);
0232     lay1->addWidget(sizes);
0233     QGridLayout *lay5 = new QGridLayout(sizes);
0234     ImageSizeCheckBox *size320 = new ImageSizeCheckBox(320, 200, sizes);
0235     ImageSizeCheckBox *size640 = new ImageSizeCheckBox(640, 480, sizes);
0236     ImageSizeCheckBox *size800 = new ImageSizeCheckBox(800, 600, sizes);
0237     ImageSizeCheckBox *size1024 = new ImageSizeCheckBox(1024, 768, sizes);
0238     ImageSizeCheckBox *size1280 = new ImageSizeCheckBox(1280, 1024, sizes);
0239     ImageSizeCheckBox *size1600 = new ImageSizeCheckBox(1600, 1200, sizes);
0240     ImageSizeCheckBox *sizeOrig = new ImageSizeCheckBox(i18n("Full size"), sizes);
0241 
0242     {
0243         int row = 0;
0244         int col = -1;
0245         lay5->addWidget(size320, row, ++col);
0246         lay5->addWidget(size640, row, ++col);
0247         lay5->addWidget(size800, row, ++col);
0248         lay5->addWidget(size1024, row, ++col);
0249         col = -1;
0250         lay5->addWidget(size1280, ++row, ++col);
0251         lay5->addWidget(size1600, row, ++col);
0252         lay5->addWidget(sizeOrig, row, ++col);
0253     }
0254 
0255     QString tmp;
0256     if ((tmp = Settings::SettingsData::instance()->HTMLSizes()) != QString::fromLatin1("")) {
0257         QStringMatcher *pattern = new QStringMatcher(QString::fromLatin1("320"));
0258         size320->setChecked(pattern->indexIn(tmp) >= 0 ? 1 : 0);
0259         pattern->setPattern(QString::fromLatin1("640"));
0260         size640->setChecked(pattern->indexIn(tmp) >= 0 ? 1 : 0);
0261         pattern->setPattern(QString::fromLatin1("800"));
0262         size800->setChecked(pattern->indexIn(tmp) >= 0 ? 1 : 0);
0263         pattern->setPattern(QString::fromLatin1("1024"));
0264         size1024->setChecked(pattern->indexIn(tmp) >= 0 ? 1 : 0);
0265         pattern->setPattern(QString::fromLatin1("1280"));
0266         size1280->setChecked(pattern->indexIn(tmp) >= 0 ? 1 : 0);
0267         pattern->setPattern(QString::fromLatin1("1600"));
0268         size1600->setChecked(pattern->indexIn(tmp) >= 0 ? 1 : 0);
0269         pattern->setPattern(QString::fromLatin1("-1"));
0270         sizeOrig->setChecked(pattern->indexIn(tmp) >= 0 ? 1 : 0);
0271     } else
0272         size800->setChecked(1);
0273 
0274     m_sizeCheckBoxes << size800 << size1024 << size1280 << size640 << size1600 << size320 << sizeOrig;
0275 
0276     lay1->addStretch(1);
0277     QGridLayout *lay6 = new QGridLayout;
0278     lay1->addLayout(lay6);
0279 }
0280 
0281 void HTMLDialog::createDestinationPage()
0282 {
0283     QWidget *destinationPage = new QWidget;
0284 
0285     KPageWidgetItem *page = new KPageWidgetItem(destinationPage, i18n("Destination"));
0286     page->setHeader(i18n("Destination"));
0287     page->setIcon(QIcon::fromTheme(QString::fromLatin1("drive-harddisk")));
0288     addPage(page);
0289 
0290     QVBoxLayout *lay1 = new QVBoxLayout(destinationPage);
0291     QGridLayout *lay2 = new QGridLayout;
0292     lay1->addLayout(lay2);
0293     int row = -1;
0294 
0295     // Base Directory
0296     QLabel *label = new QLabel(i18n("Base folder:"), destinationPage);
0297     lay2->addWidget(label, ++row, 0);
0298     QHBoxLayout *lay3 = new QHBoxLayout;
0299     lay2->addLayout(lay3, row, 1);
0300 
0301     m_baseDir = new QLineEdit(destinationPage);
0302     lay3->addWidget(m_baseDir);
0303     label->setBuddy(m_baseDir);
0304 
0305     QPushButton *but = new QPushButton(QString::fromLatin1(".."), destinationPage);
0306     lay3->addWidget(but);
0307     but->setFixedWidth(25);
0308 
0309     connect(but, &QPushButton::clicked, this, &HTMLDialog::selectDir);
0310     m_baseDir->setText(Settings::SettingsData::instance()->HTMLBaseDir());
0311 
0312     // Output Directory
0313     label = new QLabel(i18n("Gallery folder:"), destinationPage);
0314     lay2->addWidget(label, ++row, 0);
0315     m_outputDir = new QLineEdit(destinationPage);
0316     lay2->addWidget(m_outputDir, row, 1);
0317     label->setBuddy(m_outputDir);
0318 
0319     // fully "Assembled" output Directory
0320     label = new QLabel(i18n("Output folder:"), destinationPage);
0321     lay2->addWidget(label, ++row, 0);
0322     m_outputLabel = new QLabel(destinationPage);
0323     lay2->addWidget(m_outputLabel, row, 1);
0324     label->setBuddy(m_outputLabel);
0325     connect(m_baseDir, &QLineEdit::textChanged, this, &HTMLDialog::slotUpdateOutputLabel);
0326     connect(m_outputDir, &QLineEdit::textChanged, this, &HTMLDialog::slotUpdateOutputLabel);
0327     // initial text
0328     slotUpdateOutputLabel();
0329 
0330     // Destination URL
0331     label = new QLabel(i18n("URL for final destination of .kim file:"), destinationPage);
0332     label->setToolTip(i18n(
0333         "<p>If you move the gallery to a remote location, set this to the destination URL.</p>"
0334         "<p>This only affects the generated <filename>.kim</filename> file.</p>"));
0335     lay2->addWidget(label, ++row, 0);
0336     m_destURL = new QLineEdit(destinationPage);
0337     m_destURL->setText(Settings::SettingsData::instance()->HTMLDestURL());
0338     lay2->addWidget(m_destURL, row, 1);
0339     label->setBuddy(m_destURL);
0340 
0341     // Base URL
0342     label = new QLabel(i18n("Open gallery in browser:"), destinationPage);
0343     lay2->addWidget(label, ++row, 0);
0344     m_openInBrowser = new QCheckBox(destinationPage);
0345     m_openInBrowser->setChecked(true);
0346     lay2->addWidget(m_openInBrowser, row, 1);
0347     label->setBuddy(m_openInBrowser);
0348 
0349     lay1->addStretch(1);
0350 }
0351 
0352 void HTMLDialog::slotOk()
0353 {
0354     if (!checkVars())
0355         return;
0356 
0357     if (activeResolutions().count() < 1) {
0358         KMessageBox::error(nullptr, i18n("You must select at least one resolution."));
0359         return;
0360     }
0361 
0362     accept();
0363 
0364     Settings::SettingsData::instance()->setHTMLBaseDir(m_baseDir->text());
0365     Settings::SettingsData::instance()->setHTMLDestURL(m_destURL->text());
0366     Settings::SettingsData::instance()->setHTMLCopyright(m_copyright->text());
0367     Settings::SettingsData::instance()->setHTMLDate(m_date->isChecked());
0368     Settings::SettingsData::instance()->setHTMLTheme(m_themeBox->currentIndex());
0369     Settings::SettingsData::instance()->setHTMLKimFile(m_generateKimFile->isChecked());
0370     Settings::SettingsData::instance()->setHTMLInlineMovies(m_inlineMovies->isChecked());
0371     Settings::SettingsData::instance()->setHTML5Video(m_html5Video->isChecked());
0372     Settings::SettingsData::instance()->setHTML5VideoGenerate(m_html5VideoGenerate->isChecked());
0373     Settings::SettingsData::instance()->setHTMLThumbSize(m_thumbSize->value());
0374     Settings::SettingsData::instance()->setHTMLNumOfCols(m_numOfCols->value());
0375     Settings::SettingsData::instance()->setHTMLSizes(activeSizes());
0376     Settings::SettingsData::instance()->setHTMLIncludeSelections(includeSelections());
0377 
0378     Generator generator(setup(), this);
0379     generator.generate();
0380 }
0381 
0382 void HTMLDialog::selectDir()
0383 {
0384     QString dir = QFileDialog::getExistingDirectory(this,
0385                                                     i18n("Select base folder..."),
0386                                                     m_baseDir->text());
0387     if (!dir.isEmpty())
0388         m_baseDir->setText(dir);
0389 }
0390 
0391 bool HTMLDialog::checkVars()
0392 {
0393     QString outputDir = m_baseDir->text() + QString::fromLatin1("/") + m_outputDir->text();
0394 
0395     // Ensure base dir is specified
0396     QString baseDir = m_baseDir->text();
0397     if (baseDir.isEmpty()) {
0398         KMessageBox::error(this, i18n("<p>You did not specify a base folder. "
0399                                       "This is the topmost folder for your images. "
0400                                       "Each generated collection will be contained in this folder "
0401                                       "in separate subfolders.</p>"),
0402                            i18n("No Base Folder Specified"));
0403         return false;
0404     }
0405 
0406     // ensure output directory is specified
0407     if (m_outputDir->text().isEmpty()) {
0408         KMessageBox::error(this, i18n("<p>You did not specify an output folder. "
0409                                       "This is a folder containing the actual images. "
0410                                       "The folder will be a subfolder of the base folder specified above.</p>"),
0411                            i18n("No Output Folder Specified"));
0412         return false;
0413     }
0414 
0415     // ensure base dir exists
0416 #if KIO_VERSION < QT_VERSION_CHECK(5, 69, 0)
0417     QScopedPointer<KIO::StatJob> statJob(KIO::stat(QUrl::fromUserInput(baseDir), KIO::StatJob::DestinationSide, 1 /*only basic info*/));
0418 #else
0419     QScopedPointer<KIO::StatJob> statJob(KIO::statDetails(QUrl::fromUserInput(baseDir), KIO::StatJob::DestinationSide, KIO::StatDetail::StatNoDetails));
0420 #endif
0421     KJobWidgets::setWindow(statJob.data(), MainWindow::Window::theMainWindow());
0422     if (!statJob->exec()) {
0423         KMessageBox::error(this, i18n("<p>Error while reading information about %1. "
0424                                       "This is most likely because the folder does not exist.</p>"
0425                                       "<p>The error message was: %2</p>",
0426                                       baseDir, statJob->errorString()));
0427         return false;
0428     }
0429 
0430     KFileItem fileInfo(statJob->statResult(), QUrl::fromUserInput(baseDir));
0431     if (!fileInfo.isDir()) {
0432         KMessageBox::error(this, i18n("<p>%1 does not exist, is not a folder or "
0433                                       "cannot be written to.</p>",
0434                                       baseDir));
0435         return false;
0436     }
0437 
0438     // test if destination directory exists.
0439 #if KIO_VERSION < QT_VERSION_CHECK(5, 69, 0)
0440     QScopedPointer<KIO::StatJob> existsJob(KIO::stat(QUrl::fromUserInput(outputDir), KIO::StatJob::DestinationSide, 0 /*only minimal info*/));
0441 #else
0442     QScopedPointer<KIO::StatJob> existsJob(KIO::statDetails(QUrl::fromUserInput(outputDir), KIO::StatJob::DestinationSide, KIO::StatDetail::StatNoDetails));
0443 #endif
0444     KJobWidgets::setWindow(existsJob.data(), MainWindow::Window::theMainWindow());
0445     if (existsJob->exec()) {
0446         const QString question = i18n("<p>Output folder %1 already exists. "
0447                                       "Usually, this means you should specify a new folder.</p>"
0448                                       "<p>Should %2 be deleted first?</p>",
0449                                       outputDir, outputDir);
0450         const QString title = i18nc("@title", "Folder Exists");
0451         const QString dontAskAgainName = QString::fromLatin1("html_export_delete_original_directory");
0452 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0453         const auto answer = KMessageBox::questionTwoActions(this,
0454                                                             question,
0455                                                             title,
0456                                                             KStandardGuiItem::del(),
0457                                                             KStandardGuiItem::cancel(), dontAskAgainName);
0458         if (answer == KMessageBox::ButtonCode::PrimaryAction) {
0459 #else
0460         int answer = KMessageBox::warningYesNo(this,
0461                                                question,
0462                                                title, KStandardGuiItem::yes(), KStandardGuiItem::no(),
0463                                                dontAskAgainName);
0464         if (answer == KMessageBox::Yes) {
0465 #endif
0466             QScopedPointer<KJob> delJob(KIO::del(QUrl::fromUserInput(outputDir)));
0467             KJobWidgets::setWindow(delJob.data(), MainWindow::Window::theMainWindow());
0468             delJob->exec();
0469         } else
0470             return false;
0471     }
0472     return true;
0473 }
0474 
0475 QList<ImageSizeCheckBox *> HTMLDialog::activeResolutions() const
0476 {
0477     QList<ImageSizeCheckBox *> res;
0478     for (QList<ImageSizeCheckBox *>::ConstIterator sizeIt = m_sizeCheckBoxes.begin(); sizeIt != m_sizeCheckBoxes.end(); ++sizeIt) {
0479         if ((*sizeIt)->isChecked())
0480             res << *sizeIt;
0481     }
0482     return res;
0483 }
0484 
0485 QString HTMLDialog::activeSizes() const
0486 {
0487     QString res;
0488     for (QList<ImageSizeCheckBox *>::ConstIterator sizeIt = m_sizeCheckBoxes.begin(); sizeIt != m_sizeCheckBoxes.end(); ++sizeIt) {
0489         if ((*sizeIt)->isChecked()) {
0490             if (res.length() > 0)
0491                 res.append(QString::fromLatin1(","));
0492             res.append(QString::number((*sizeIt)->width()));
0493         }
0494     }
0495     return res;
0496 }
0497 
0498 QString HTMLDialog::includeSelections() const
0499 {
0500     QString sel;
0501     Setup setupChoices = setup();
0502 
0503     for (QMap<QString, QCheckBox *>::ConstIterator it = m_whatToIncludeMap.begin(); it != m_whatToIncludeMap.end(); ++it) {
0504         QString name = it.key();
0505         if (setupChoices.includeCategory(name)) {
0506             if (sel.length() > 0)
0507                 sel.append(QString::fromLatin1(","));
0508             sel.append(name);
0509         }
0510     }
0511     return sel;
0512 }
0513 
0514 void HTMLDialog::populateThemesCombo()
0515 {
0516     QStringList dirs = QStandardPaths::locateAll(
0517         QStandardPaths::DataLocation,
0518         QString::fromLocal8Bit("themes/"),
0519         QStandardPaths::LocateDirectory);
0520     int i = 0;
0521     int theme = 0;
0522     int defaultthemes = 0;
0523     qCDebug(HTMLGeneratorLog) << "Theme directories:" << dirs;
0524     for (QStringList::Iterator it = dirs.begin(); it != dirs.end(); ++it) {
0525         QDir dir(*it);
0526         qCDebug(HTMLGeneratorLog) << "Searching themes in:" << dir;
0527         QStringList themes = dir.entryList(QDir::Dirs | QDir::Readable);
0528         for (QStringList::Iterator it = themes.begin(); it != themes.end(); ++it) {
0529             qCDebug(HTMLGeneratorLog) << " *" << *it;
0530             if (*it == QString::fromLatin1(".") || *it == QString::fromLatin1(".."))
0531                 continue;
0532             QString themePath = QString::fromLatin1("%1/%2/").arg(dir.path(), *it);
0533 
0534             KConfig themeconfig(QString::fromLatin1("%1/kphotoalbum.theme").arg(themePath), KConfig::SimpleConfig);
0535             KConfigGroup config = themeconfig.group("theme");
0536             QString themeName = config.readEntry("Name");
0537             // without the name, we can't show anything useful for the user to choose
0538             if (themeName.trimmed().isEmpty())
0539                 continue;
0540             QString themeAuthor = config.readEntry("Author");
0541             m_themeAuthors << themeAuthor; // save author to display later
0542             QString themeDefault = config.readEntry("Default");
0543             QString themeDescription = config.readEntry("Description");
0544             m_themeDescriptions << themeDescription; // save description to display later
0545 
0546             // m_themeBox->insertItem( i, i18n( "%1 (by %2)",themeName, themeAuthor ) ); // combined alternative
0547             m_themeBox->insertItem(i, i18n("%1", themeName));
0548             m_themes.insert(i, themePath);
0549 
0550             if (themeDefault == QString::fromLatin1("true")) {
0551                 theme = i;
0552                 defaultthemes++;
0553             }
0554             i++;
0555         }
0556     }
0557     if (m_themeBox->count() < 1) {
0558         KMessageBox::error(this, i18n("Could not find any themes - this is very likely an installation error"));
0559     }
0560     if ((Settings::SettingsData::instance()->HTMLTheme() >= 0) && (Settings::SettingsData::instance()->HTMLTheme() < m_themeBox->count()))
0561         m_themeBox->setCurrentIndex(Settings::SettingsData::instance()->HTMLTheme());
0562     else {
0563         m_themeBox->setCurrentIndex(theme);
0564         if (defaultthemes > 1)
0565             KMessageBox::information(this, i18n("More than one theme is set as default, using theme %1", m_themeBox->currentText()));
0566     }
0567 }
0568 
0569 void HTMLDialog::displayThemeDescription(int themenr)
0570 {
0571     // SLOT: update m_themeInfo label whenever the m_theme QComboBox changes.
0572     QString outtxt = i18nc("This is to show the author of the theme. E.g. copyright character (&#169;) by itself will work fine on this context if no proper word is available in your language.", "by ");
0573     outtxt.append(m_themeAuthors[themenr]);
0574     outtxt.append(i18n("\n "));
0575     outtxt.append(m_themeDescriptions[themenr]);
0576     m_themeInfo->setText(outtxt);
0577     // Instead of two separate lists for authors and descriptions one could have a combined one by appending the text prior to storing within populateThemesCombo(),
0578     // however, storing author and descriptions separately might be cleaner.
0579 }
0580 
0581 void HTMLDialog::slotUpdateOutputLabel()
0582 {
0583     QString outputDir = QDir(m_baseDir->text()).filePath(m_outputDir->text());
0584     auto labelPalette = m_outputLabel->palette();
0585     // feedback on validity:
0586     if (outputDir == m_baseDir->text()) {
0587         KColorScheme::adjustForeground(labelPalette, KColorScheme::ForegroundRole::NegativeText, QPalette::WindowText);
0588         KColorScheme::adjustBackground(labelPalette, KColorScheme::BackgroundRole::NegativeBackground, QPalette::Window);
0589         outputDir.append(i18n("<p>Gallery folder cannot be empty.</p>"));
0590     } else if (QDir(outputDir).exists()) {
0591         KColorScheme::adjustForeground(labelPalette, KColorScheme::ForegroundRole::NegativeText, QPalette::WindowText);
0592         KColorScheme::adjustBackground(labelPalette, KColorScheme::BackgroundRole::NegativeBackground, QPalette::Window);
0593         outputDir.append(i18n("<p>The output folder already exists.</p>"));
0594     } else {
0595         labelPalette = palette();
0596     }
0597     m_outputLabel->setPalette(labelPalette);
0598     m_outputLabel->setText(outputDir);
0599 }
0600 
0601 void HTMLDialog::slotSuggestOutputDir()
0602 {
0603     if (m_outputDir->text().isEmpty()) {
0604         // the title is often an adequate directory name:
0605         m_outputDir->setText(m_title->text());
0606     }
0607 }
0608 
0609 bool HTMLDialog::event(QEvent *event)
0610 {
0611     if (event->type() == QEvent::PaletteChange)
0612         slotUpdateOutputLabel();
0613     return KPageDialog::event(event);
0614 }
0615 
0616 int HTMLDialog::exec(const DB::FileNameList &list)
0617 {
0618     if (list.empty()) {
0619         qCWarning(HTMLGeneratorLog) << "HTMLDialog called without images for export";
0620         return false;
0621     }
0622     m_list = list;
0623     return QDialog::exec();
0624 }
0625 
0626 Setup HTMLGenerator::HTMLDialog::setup() const
0627 {
0628     Setup setup;
0629     setup.setTitle(m_title->text());
0630     setup.setBaseDir(m_baseDir->text());
0631     if (m_openInBrowser->isEnabled()) {
0632         setup.setBaseURL(m_baseDir->text());
0633     }
0634     setup.setDestURL(m_destURL->text());
0635     setup.setOutputDir(m_outputDir->text());
0636     setup.setThumbSize(m_thumbSize->value());
0637     setup.setCopyright(m_copyright->text());
0638     setup.setDate(m_date->isChecked());
0639     setup.setDescription(m_description->toPlainText());
0640     setup.setNumOfCols(m_numOfCols->value());
0641     setup.setGenerateKimFile(m_generateKimFile->isChecked());
0642     setup.setThemePath(m_themes[m_themeBox->currentIndex()]);
0643     for (QMap<QString, QCheckBox *>::ConstIterator includeIt = m_whatToIncludeMap.begin();
0644          includeIt != m_whatToIncludeMap.end(); ++includeIt) {
0645         setup.setIncludeCategory(includeIt.key(), includeIt.value()->isChecked());
0646     }
0647     setup.setImageList(m_list);
0648 
0649     setup.setResolutions(activeResolutions());
0650     setup.setInlineMovies(m_inlineMovies->isChecked());
0651     setup.setHtml5Video(m_html5Video->isChecked());
0652     setup.setHtml5VideoGenerate(m_html5VideoGenerate->isChecked());
0653     return setup;
0654 }
0655 
0656 // vi:expandtab:tabstop=4 shiftwidth=4:
0657 
0658 #include "moc_HTMLDialog.cpp"