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"