File indexing completed on 2024-05-12 05:13:29

0001 /*
0002    SPDX-FileCopyrightText: 2015-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "themeeditorpage.h"
0008 #include "contactprintthemepreview.h"
0009 #include "desktopfilepage.h"
0010 #include "editorpage.h"
0011 #include "themeeditortabwidget.h"
0012 #include "themeeditorwidget.h"
0013 #include "themesession.h"
0014 
0015 #include "contactprintthemeeditor_debug.h"
0016 #include <KLocalizedString>
0017 #include <KMessageBox>
0018 #include <KZip>
0019 #include <QInputDialog>
0020 #include <QTemporaryDir>
0021 #include <QUrl>
0022 
0023 #include <QDir>
0024 #include <QFileDialog>
0025 #include <QHBoxLayout>
0026 #include <QPointer>
0027 
0028 ThemeEditorPage::ThemeEditorPage(const QString &projectDir, const QString &themeName, QWidget *parent)
0029     : QWidget(parent)
0030     , mThemeSession(new GrantleeThemeEditor::ThemeSession(projectDir, QStringLiteral("headerthemeeditor")))
0031 {
0032     auto lay = new QHBoxLayout(this);
0033     mTabWidget = new GrantleeThemeEditor::ThemeEditorTabWidget;
0034     connect(mTabWidget, &GrantleeThemeEditor::ThemeEditorTabWidget::currentChanged, this, &ThemeEditorPage::slotCurrentWidgetChanged);
0035     lay->addWidget(mTabWidget);
0036     mEditorPage = new EditorPage(EditorPage::MainPage, projectDir);
0037     mEditorPage->setPageFileName(QStringLiteral("theme.html"));
0038     connect(mEditorPage, &EditorPage::needUpdateViewer, this, &ThemeEditorPage::slotUpdateViewer);
0039     connect(mEditorPage, &EditorPage::changed, this, &ThemeEditorPage::slotChanged);
0040     mTabWidget->addTab(mEditorPage, i18n("Editor (%1)", QStringLiteral("theme.html")));
0041 
0042     GrantleeThemeEditor::DesktopFilePage::DesktopFileOptions opt;
0043     mDesktopPage = new GrantleeThemeEditor::DesktopFilePage(QStringLiteral("theme.html"), opt, this);
0044     mDesktopPage->setDefaultDesktopName(QStringLiteral("theme.desktop"));
0045     mDesktopPage->setThemeName(themeName);
0046     mTabWidget->addTab(mDesktopPage, i18n("Desktop File"));
0047 
0048     connect(mDesktopPage,
0049             &GrantleeThemeEditor::DesktopFilePage::mainFileNameChanged,
0050             mEditorPage->preview(),
0051             &GrantleeThemeEditor::PreviewWidget::slotMainFileNameChanged);
0052     connect(mDesktopPage,
0053             &GrantleeThemeEditor::DesktopFilePage::mainFileNameChanged,
0054             mTabWidget,
0055             &GrantleeThemeEditor::ThemeEditorTabWidget::slotMainFileNameChanged);
0056     connect(mDesktopPage, &GrantleeThemeEditor::DesktopFilePage::changed, this, &ThemeEditorPage::slotChanged);
0057     connect(mTabWidget, &GrantleeThemeEditor::ThemeEditorTabWidget::tabCloseRequested, this, &ThemeEditorPage::slotCloseTab);
0058 }
0059 
0060 ThemeEditorPage::~ThemeEditorPage()
0061 {
0062     qDeleteAll(mExtraPage);
0063     mExtraPage.clear();
0064     delete mThemeSession;
0065 }
0066 
0067 void ThemeEditorPage::slotCurrentWidgetChanged(int index)
0068 {
0069     if (index < 0) {
0070         return;
0071     }
0072     auto page = dynamic_cast<GrantleeThemeEditor::EditorPage *>(mTabWidget->widget(index));
0073     Q_EMIT canInsertFile(page);
0074 }
0075 
0076 void ThemeEditorPage::updatePreview()
0077 {
0078     mEditorPage->preview()->updateViewer();
0079 }
0080 
0081 void ThemeEditorPage::slotChanged()
0082 {
0083     setChanged(true);
0084 }
0085 
0086 void ThemeEditorPage::setChanged(bool b)
0087 {
0088     if (mChanged != b) {
0089         mChanged = b;
0090         Q_EMIT changed(b);
0091     }
0092 }
0093 
0094 void ThemeEditorPage::slotUpdateViewer()
0095 {
0096     if (themeWasChanged()) {
0097         saveTheme(false);
0098     }
0099     mEditorPage->preview()->updateViewer();
0100 }
0101 
0102 void ThemeEditorPage::slotCloseTab(int index)
0103 {
0104     mTabWidget->removeTab(index);
0105     setChanged(true);
0106 }
0107 
0108 void ThemeEditorPage::insertFile()
0109 {
0110     QWidget *w = mTabWidget->currentWidget();
0111     if (!w) {
0112         return;
0113     }
0114     auto page = dynamic_cast<GrantleeThemeEditor::EditorPage *>(w);
0115     if (page) {
0116         const QString fileName = QFileDialog::getOpenFileName(this);
0117         if (!fileName.isEmpty()) {
0118             page->insertFile(fileName);
0119         }
0120     }
0121 }
0122 
0123 bool ThemeEditorPage::themeWasChanged() const
0124 {
0125     return mChanged;
0126 }
0127 
0128 void ThemeEditorPage::installTheme(const QString &themePath)
0129 {
0130     QDir dir(themePath);
0131     QDir themeDir(themePath + QLatin1Char('/') + mDesktopPage->themeName());
0132     if (themeDir.exists()) {
0133         const int answer = KMessageBox::questionTwoActions(this,
0134                                                            i18n("Theme already exists. Do you want to overwrite it?"),
0135                                                            i18n("Theme already exists"),
0136                                                            KStandardGuiItem::overwrite(),
0137                                                            KStandardGuiItem::cancel());
0138         if (answer == KMessageBox::ButtonCode::SecondaryAction) {
0139             return;
0140         }
0141     } else {
0142         if (!dir.mkdir(mDesktopPage->themeName())) {
0143             KMessageBox::error(this, i18n("Cannot create theme folder."));
0144             return;
0145         }
0146     }
0147     const QString newPath = themePath + QLatin1Char('/') + mDesktopPage->themeName();
0148     mEditorPage->installTheme(newPath);
0149     for (EditorPage *page : std::as_const(mExtraPage)) {
0150         page->installTheme(newPath);
0151     }
0152     mDesktopPage->installTheme(newPath);
0153     KMessageBox::information(this, i18n("Theme installed in \"%1\"", themeDir.absolutePath()));
0154 }
0155 
0156 void ThemeEditorPage::uploadTheme()
0157 {
0158 #if 0
0159     // force update for screenshot
0160     mEditorPage->preview()->updateViewer();
0161     QTemporaryDir tmp;
0162     const QString themename = mDesktopPage->themeName();
0163     const QString zipFileName = tmp.path() + QLatin1Char('/') + themename + QLatin1StringView(".zip");
0164     KZip *zip = new KZip(zipFileName);
0165     if (zip->open(QIODevice::WriteOnly)) {
0166         const QString previewFileName = tmp.path() + QLatin1Char('/') + themename + QLatin1StringView("_preview.png");
0167         // qCDebug(CONTACTPRINTTHEMEEDITOR_LOG)<<" previewFileName"<<previewFileName;
0168         QStringList lst;
0169         lst << previewFileName;
0170         mEditorPage->preview()->createScreenShot(lst);
0171 
0172         const bool fileAdded = zip->addLocalFile(previewFileName, themename + QLatin1Char('/') + QLatin1StringView("theme_preview.png"));
0173         if (!fileAdded) {
0174             KMessageBox::error(this, i18n("We cannot add preview file in zip file"), i18n("Failed to add file."));
0175             delete zip;
0176             return;
0177         }
0178 
0179         createZip(themename, zip);
0180         zip->close();
0181         // qCDebug(CONTACTPRINTTHEMEEDITOR_LOG)<< "zipFilename"<<zipFileName;
0182 
0183         QPointer<KNS3::UploadDialog> dialog = new KNS3::UploadDialog(QStringLiteral("messageviewer_header_themes.knsrc"), this);
0184         dialog->setUploadFile(QUrl::fromLocalFile(zipFileName));
0185         dialog->setUploadName(themename);
0186         dialog->setPreviewImageFile(0, QUrl::fromLocalFile(previewFileName));
0187         const QString description = mDesktopPage->description();
0188         dialog->setDescription(description.isEmpty() ? i18n("My favorite KMail header") : description);
0189         dialog->exec();
0190         delete dialog;
0191     } else {
0192         qCDebug(CONTACTPRINTTHEMEEDITOR_LOG) << " We can't open in zip write mode";
0193     }
0194     delete zip;
0195 #endif
0196 }
0197 
0198 void ThemeEditorPage::createZip(const QString &themeName, KZip *zip)
0199 {
0200     mEditorPage->createZip(themeName, zip);
0201 
0202     for (EditorPage *page : std::as_const(mExtraPage)) {
0203         page->createZip(themeName, zip);
0204     }
0205     mDesktopPage->createZip(themeName, zip);
0206 }
0207 
0208 void ThemeEditorPage::addExtraPage()
0209 {
0210     bool ok = false;
0211     QString filename = QInputDialog::getText(this, i18n("Filename of extra page"), i18n("Filename:"), {}, {}, &ok);
0212     if (ok) {
0213         if (!filename.trimmed().isEmpty()) {
0214             if (!filename.endsWith(QLatin1StringView(".html")) && !filename.endsWith(QLatin1StringView(".css"))
0215                 && !filename.endsWith(QLatin1StringView(".js"))) {
0216                 filename += QLatin1StringView(".html");
0217             }
0218             createExtraPage(filename);
0219             mThemeSession->addExtraPage(filename);
0220             setChanged(true);
0221         }
0222     }
0223 }
0224 
0225 EditorPage *ThemeEditorPage::createExtraPage(const QString &filename)
0226 {
0227     auto extraPage = new EditorPage(EditorPage::ExtraPage, QString());
0228     connect(extraPage, &EditorPage::changed, this, &ThemeEditorPage::slotChanged);
0229     extraPage->setPageFileName(filename);
0230     mTabWidget->addTab(extraPage, filename);
0231     mTabWidget->setCurrentWidget(extraPage);
0232     mExtraPage.append(extraPage);
0233     return extraPage;
0234 }
0235 
0236 void ThemeEditorPage::storeTheme(const QString &directory)
0237 {
0238     const QString themeDirectory = directory.isEmpty() ? projectDirectory() : directory;
0239     mEditorPage->saveTheme(themeDirectory);
0240 
0241     for (EditorPage *page : std::as_const(mExtraPage)) {
0242         page->saveTheme(themeDirectory);
0243     }
0244     mDesktopPage->saveTheme(themeDirectory);
0245     mThemeSession->setMainPageFileName(mDesktopPage->filename());
0246     mThemeSession->writeSession(directory);
0247     if (directory.isEmpty()) {
0248         setChanged(false);
0249     }
0250 }
0251 
0252 bool ThemeEditorPage::saveTheme(bool withConfirmation)
0253 {
0254     if (themeWasChanged()) {
0255         if (withConfirmation) {
0256             const int result = KMessageBox::questionTwoActionsCancel(this,
0257                                                                      i18n("Do you want to save current project?"),
0258                                                                      i18n("Save current project"),
0259                                                                      KStandardGuiItem::save(),
0260                                                                      KStandardGuiItem::discard());
0261             if (result == KMessageBox::ButtonCode::PrimaryAction) {
0262                 storeTheme();
0263             } else if (result == KMessageBox::Cancel) {
0264                 return false;
0265             }
0266         } else {
0267             storeTheme();
0268         }
0269     }
0270     setChanged(false);
0271     return true;
0272 }
0273 
0274 void ThemeEditorPage::loadTheme(const QString &filename)
0275 {
0276     if (mThemeSession->loadSession(filename)) {
0277         mDesktopPage->loadTheme(mThemeSession->projectDirectory());
0278         mEditorPage->loadTheme(mThemeSession->projectDirectory() + QLatin1Char('/') + mThemeSession->mainPageFileName());
0279         mEditorPage->preview()->setThemePath(mThemeSession->projectDirectory(), mThemeSession->mainPageFileName());
0280 
0281         const QStringList lstExtraPages = mThemeSession->extraPages();
0282         for (const QString &page : lstExtraPages) {
0283             EditorPage *extraPage = createExtraPage(page);
0284             extraPage->loadTheme(mThemeSession->projectDirectory() + QLatin1Char('/') + page);
0285         }
0286         mTabWidget->setCurrentIndex(0);
0287         setChanged(false);
0288     }
0289 }
0290 
0291 void ThemeEditorPage::reloadConfig()
0292 {
0293     mEditorPage->preview()->loadConfig();
0294 }
0295 
0296 QString ThemeEditorPage::projectDirectory() const
0297 {
0298     return mThemeSession->projectDirectory();
0299 }
0300 
0301 void ThemeEditorPage::saveThemeAs(const QString &directory)
0302 {
0303     storeTheme(directory);
0304 }
0305 
0306 #include "moc_themeeditorpage.cpp"