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

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