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

0001 /*
0002    SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 #include "themeeditormainwindow.h"
0007 #include "managethemes.h"
0008 #include "newthemedialog.h"
0009 #include "themeconfiguredialog.h"
0010 #include "themeeditorpage.h"
0011 
0012 #include <KActionCollection>
0013 #include <KAuthorized>
0014 #include <KConfigGroup>
0015 #include <KLocalizedString>
0016 #include <KMessageBox>
0017 #include <KRecentFilesAction>
0018 #include <KStandardAction>
0019 #include <KToggleAction>
0020 #include <QAction>
0021 #include <QFileDialog>
0022 
0023 #include <KSharedConfig>
0024 #include <QActionGroup>
0025 #include <QApplication>
0026 #include <QCloseEvent>
0027 #include <QPointer>
0028 #include <QStandardPaths>
0029 
0030 ThemeEditorMainWindow::ThemeEditorMainWindow()
0031     : KXmlGuiWindow()
0032 {
0033     setupActions();
0034     setupGUI();
0035     updateActions();
0036     readConfig();
0037 }
0038 
0039 ThemeEditorMainWindow::~ThemeEditorMainWindow() = default;
0040 
0041 void ThemeEditorMainWindow::writeConfig()
0042 {
0043     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0044 
0045     KConfigGroup group = config->group(QStringLiteral("ThemeEditorMainWindow"));
0046     group.writeEntry("Size", size());
0047     mRecentFileAction->saveEntries(group);
0048 }
0049 
0050 void ThemeEditorMainWindow::readConfig()
0051 {
0052     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0053     KConfigGroup group = KConfigGroup(config, QStringLiteral("ThemeEditorMainWindow"));
0054     const QSize sizeDialog = group.readEntry("Size", QSize(600, 400));
0055     if (sizeDialog.isValid()) {
0056         resize(sizeDialog);
0057     }
0058 }
0059 
0060 void ThemeEditorMainWindow::updateActions()
0061 {
0062     const bool projectDirectoryIsEmpty = (mThemeEditor != nullptr);
0063     mAddExtraPage->setEnabled(projectDirectoryIsEmpty);
0064     mCloseAction->setEnabled(projectDirectoryIsEmpty);
0065     if (mUploadTheme) {
0066         mUploadTheme->setEnabled(projectDirectoryIsEmpty);
0067     }
0068     mSaveAction->setEnabled(projectDirectoryIsEmpty);
0069     mInstallTheme->setEnabled(projectDirectoryIsEmpty);
0070     mInsertFile->setEnabled(projectDirectoryIsEmpty);
0071     mPrintingMode->setEnabled(projectDirectoryIsEmpty);
0072     mNormalMode->setEnabled(projectDirectoryIsEmpty);
0073     mUpdateView->setEnabled(projectDirectoryIsEmpty);
0074     mSaveAsAction->setEnabled(projectDirectoryIsEmpty);
0075 }
0076 
0077 void ThemeEditorMainWindow::setupActions()
0078 {
0079     mRecentFileAction = new KRecentFilesAction(i18n("Load Recent Theme..."), this);
0080     connect(mRecentFileAction, &KRecentFilesAction::urlSelected, this, &ThemeEditorMainWindow::slotThemeSelected);
0081     actionCollection()->addAction(QStringLiteral("load_recent_theme"), mRecentFileAction);
0082     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0083     KConfigGroup groupConfig = config->group(QStringLiteral("ThemeEditorMainWindow"));
0084     mRecentFileAction->loadEntries(groupConfig);
0085 
0086     mAddExtraPage = new QAction(i18n("Add Extra Page..."), this);
0087     connect(mAddExtraPage, &QAction::triggered, this, &ThemeEditorMainWindow::slotAddExtraPage);
0088     actionCollection()->addAction(QStringLiteral("add_extra_page"), mAddExtraPage);
0089 
0090     if (KAuthorized::authorize(QStringLiteral("ghns"))) {
0091         mUploadTheme = new QAction(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")), i18n("Upload theme..."), this);
0092         connect(mUploadTheme, &QAction::triggered, this, &ThemeEditorMainWindow::slotUploadTheme);
0093         actionCollection()->addAction(QStringLiteral("upload_theme"), mUploadTheme);
0094     }
0095 
0096     mNewThemeAction = KStandardAction::openNew(this, &ThemeEditorMainWindow::slotNewTheme, actionCollection());
0097     mNewThemeAction->setText(i18n("New theme..."));
0098 
0099     mOpenAction = KStandardAction::open(this, &ThemeEditorMainWindow::slotOpenTheme, actionCollection());
0100     mOpenAction->setText(i18n("Open theme..."));
0101     mSaveAction = KStandardAction::save(this, &ThemeEditorMainWindow::slotSaveTheme, actionCollection());
0102     mSaveAction->setText(i18n("Save theme"));
0103 
0104     mSaveAsAction = KStandardAction::saveAs(this, &ThemeEditorMainWindow::slotSaveAsTheme, actionCollection());
0105     mSaveAsAction->setText(i18n("Save theme as..."));
0106 
0107     mCloseAction = KStandardAction::close(this, &ThemeEditorMainWindow::slotCloseTheme, actionCollection());
0108     KStandardAction::quit(this, &ThemeEditorMainWindow::slotQuitApp, actionCollection());
0109     KStandardAction::preferences(this, &ThemeEditorMainWindow::slotConfigure, actionCollection());
0110 
0111     mInstallTheme = new QAction(i18n("Install theme"), this);
0112     actionCollection()->addAction(QStringLiteral("install_theme"), mInstallTheme);
0113     connect(mInstallTheme, &QAction::triggered, this, &ThemeEditorMainWindow::slotInstallTheme);
0114 
0115     mInsertFile = new QAction(i18n("Insert File..."), this);
0116     actionCollection()->addAction(QStringLiteral("insert_file"), mInsertFile);
0117     connect(mInsertFile, &QAction::triggered, this, &ThemeEditorMainWindow::slotInsertFile);
0118 
0119     auto group = new QActionGroup(this);
0120 
0121     mPrintingMode = new KToggleAction(i18n("Printing mode"), this);
0122     actionCollection()->addAction(QStringLiteral("printing_mode"), mPrintingMode);
0123     connect(mPrintingMode, &KToggleAction::triggered, this, &ThemeEditorMainWindow::slotPrintingMode);
0124     group->addAction(mPrintingMode);
0125 
0126     mNormalMode = new KToggleAction(i18n("Normal mode"), this);
0127     mNormalMode->setChecked(true);
0128     actionCollection()->addAction(QStringLiteral("normal_mode"), mNormalMode);
0129     connect(mNormalMode, &KToggleAction::triggered, this, &ThemeEditorMainWindow::slotNormalMode);
0130     group->addAction(mNormalMode);
0131 
0132     mManageTheme = new QAction(i18n("Manage themes..."), this);
0133     connect(mManageTheme, &QAction::triggered, this, &ThemeEditorMainWindow::slotManageTheme);
0134     actionCollection()->addAction(QStringLiteral("manage_themes"), mManageTheme);
0135 
0136     mUpdateView = new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")), i18n("Update view"), this);
0137     actionCollection()->setDefaultShortcut(mUpdateView, QKeySequence(Qt::Key_F5));
0138     connect(mUpdateView, &QAction::triggered, this, &ThemeEditorMainWindow::slotUpdateView);
0139     actionCollection()->addAction(QStringLiteral("update_view"), mUpdateView);
0140 }
0141 
0142 void ThemeEditorMainWindow::slotManageTheme()
0143 {
0144     QPointer<GrantleeThemeEditor::ManageThemes> dialog = new GrantleeThemeEditor::ManageThemes(QStringLiteral("messageviewer/themes/"), this);
0145     dialog->exec();
0146     delete dialog;
0147 }
0148 
0149 void ThemeEditorMainWindow::slotNormalMode()
0150 {
0151     mThemeEditor->setPrinting(false);
0152 }
0153 
0154 void ThemeEditorMainWindow::slotPrintingMode()
0155 {
0156     mThemeEditor->setPrinting(true);
0157 }
0158 
0159 void ThemeEditorMainWindow::slotInsertFile()
0160 {
0161     mThemeEditor->insertFile();
0162 }
0163 
0164 void ThemeEditorMainWindow::slotConfigure()
0165 {
0166     QPointer<ThemeConfigureDialog> dialog = new ThemeConfigureDialog(this);
0167     if (dialog->exec()) {
0168         if (mThemeEditor) {
0169             mThemeEditor->reloadConfig();
0170         }
0171     }
0172     delete dialog;
0173 }
0174 
0175 void ThemeEditorMainWindow::slotInstallTheme()
0176 {
0177     // Save before installing :)
0178     if (slotSaveTheme()) {
0179         const QString localThemePath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1StringView("/messageviewer/themes/");
0180         QDir().mkpath(localThemePath);
0181         mThemeEditor->installTheme(localThemePath);
0182     }
0183 }
0184 
0185 void ThemeEditorMainWindow::slotUploadTheme()
0186 {
0187     // Save before upload :)
0188     if (slotSaveTheme()) {
0189         mThemeEditor->uploadTheme();
0190     }
0191 }
0192 
0193 bool ThemeEditorMainWindow::slotSaveTheme()
0194 {
0195     bool result = false;
0196     if (mThemeEditor) {
0197         result = mThemeEditor->saveTheme(false);
0198         mSaveAction->setEnabled(!result);
0199     }
0200     return result;
0201 }
0202 
0203 void ThemeEditorMainWindow::slotCloseTheme()
0204 {
0205     saveCurrentProject(SaveAndCloseTheme);
0206 }
0207 
0208 void ThemeEditorMainWindow::slotOpenTheme()
0209 {
0210     if (!saveCurrentProject(SaveOnly)) {
0211         return;
0212     }
0213 
0214     const QString directory = QFileDialog::getExistingDirectory(this, i18n("Select theme directory"));
0215     if (directory.isEmpty()) {
0216         return;
0217     }
0218     closeThemeEditor();
0219     if (loadTheme(directory)) {
0220         mRecentFileAction->addUrl(QUrl::fromLocalFile(directory));
0221     }
0222     mSaveAction->setEnabled(false);
0223 }
0224 
0225 bool ThemeEditorMainWindow::loadTheme(const QString &directory)
0226 {
0227     if (!directory.isEmpty()) {
0228         const QString filename = directory + QLatin1StringView("/theme.themerc");
0229         if (!QFileInfo::exists(filename)) {
0230             KMessageBox::error(this, i18n("Directory does not contain a theme file. We cannot load theme."));
0231             return false;
0232         }
0233 
0234         mThemeEditor = new ThemeEditorPage(QString(), QString());
0235         connect(mThemeEditor, &ThemeEditorPage::changed, mSaveAction, &QAction::setEnabled);
0236         connect(mThemeEditor, &ThemeEditorPage::canInsertFile, this, &ThemeEditorMainWindow::slotCanInsertFile);
0237         mThemeEditor->loadTheme(filename);
0238         setCentralWidget(mThemeEditor);
0239         updateActions();
0240     }
0241     return true;
0242 }
0243 
0244 void ThemeEditorMainWindow::slotAddExtraPage()
0245 {
0246     if (mThemeEditor) {
0247         mThemeEditor->addExtraPage();
0248     }
0249 }
0250 
0251 void ThemeEditorMainWindow::closeThemeEditor()
0252 {
0253     delete mThemeEditor;
0254     mThemeEditor = nullptr;
0255     setCentralWidget(nullptr);
0256     updateActions();
0257 }
0258 
0259 bool ThemeEditorMainWindow::saveCurrentProject(ActionSaveTheme act)
0260 {
0261     if (mThemeEditor) {
0262         if (!mThemeEditor->saveTheme()) {
0263             return false;
0264         }
0265     }
0266     switch (act) {
0267     case SaveOnly:
0268         break;
0269     case SaveAndCloseTheme:
0270         closeThemeEditor();
0271         break;
0272     case SaveAndCreateNewTheme: {
0273         delete mThemeEditor;
0274         mThemeEditor = nullptr;
0275         QPointer<GrantleeThemeEditor::NewThemeDialog> dialog = new GrantleeThemeEditor::NewThemeDialog(this);
0276         QString newTheme;
0277         QString projectDirectory;
0278         if (dialog->exec()) {
0279             newTheme = dialog->themeName();
0280             projectDirectory = dialog->directory();
0281         }
0282         if (!projectDirectory.isEmpty()) {
0283             mRecentFileAction->addUrl(QUrl::fromLocalFile(projectDirectory));
0284             mThemeEditor = new ThemeEditorPage(projectDirectory, newTheme);
0285             connect(mThemeEditor, &ThemeEditorPage::changed, mSaveAction, &QAction::setEnabled);
0286             connect(mThemeEditor, &ThemeEditorPage::canInsertFile, this, &ThemeEditorMainWindow::slotCanInsertFile);
0287             setCentralWidget(mThemeEditor);
0288         } else {
0289             setCentralWidget(nullptr);
0290         }
0291         delete dialog;
0292         updateActions();
0293         break;
0294     }
0295     }
0296 
0297     return true;
0298 }
0299 
0300 void ThemeEditorMainWindow::slotNewTheme()
0301 {
0302     saveCurrentProject(SaveAndCreateNewTheme);
0303 }
0304 
0305 void ThemeEditorMainWindow::closeEvent(QCloseEvent *e)
0306 {
0307     if (!saveCurrentProject(SaveAndCloseTheme)) {
0308         e->ignore();
0309     } else {
0310         writeConfig();
0311         e->accept();
0312     }
0313 }
0314 
0315 void ThemeEditorMainWindow::slotQuitApp()
0316 {
0317     if (saveCurrentProject(SaveAndCloseTheme)) {
0318         writeConfig();
0319         qApp->quit();
0320     }
0321 }
0322 
0323 void ThemeEditorMainWindow::slotUpdateView()
0324 {
0325     if (mThemeEditor) {
0326         mThemeEditor->saveTheme(false);
0327         mThemeEditor->updatePreview();
0328     }
0329 }
0330 
0331 void ThemeEditorMainWindow::slotCanInsertFile(bool b)
0332 {
0333     mInsertFile->setEnabled(b);
0334 }
0335 
0336 void ThemeEditorMainWindow::slotThemeSelected(const QUrl &url)
0337 {
0338     if (!saveCurrentProject(SaveAndCloseTheme)) {
0339         return;
0340     }
0341     loadTheme(url.path());
0342     mSaveAction->setEnabled(false);
0343 }
0344 
0345 void ThemeEditorMainWindow::slotSaveAsTheme()
0346 {
0347     const QString directory = QFileDialog::getExistingDirectory(this, i18n("Select theme directory"));
0348     if (!directory.isEmpty()) {
0349         if (mThemeEditor) {
0350             mThemeEditor->saveThemeAs(directory);
0351         }
0352     }
0353 }
0354 
0355 #include "moc_themeeditormainwindow.cpp"