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