diff --git a/kerfuffle/CMakeLists.txt b/kerfuffle/CMakeLists.txt --- a/kerfuffle/CMakeLists.txt +++ b/kerfuffle/CMakeLists.txt @@ -22,6 +22,7 @@ mimetypes.cpp plugin.cpp pluginmanager.cpp + pluginsettingspage.cpp archiveentry.cpp options.cpp ) @@ -33,6 +34,7 @@ extractiondialog.ui extractionsettingspage.ui generalsettingspage.ui + pluginsettingspage.ui previewsettingspage.ui propertiesdialog.ui compressionoptionswidget.ui diff --git a/kerfuffle/ark.kcfg b/kerfuffle/ark.kcfg --- a/kerfuffle/ark.kcfg +++ b/kerfuffle/ark.kcfg @@ -46,6 +46,10 @@ true + + + + diff --git a/kerfuffle/plugin.h b/kerfuffle/plugin.h --- a/kerfuffle/plugin.h +++ b/kerfuffle/plugin.h @@ -86,6 +86,12 @@ KPluginMetaData metaData() const; /** + * @return Whether the executables required for a functional plugin are installed. + * This is true if all the read-only executables are found in the path. + */ + bool hasRequiredExecutables() const; + + /** * @return Whether the plugin is ready to be used. * This implies isEnabled(), while an enabled plugin may not be valid. * A read-write plugin downgraded to read-only is still valid. diff --git a/kerfuffle/plugin.cpp b/kerfuffle/plugin.cpp --- a/kerfuffle/plugin.cpp +++ b/kerfuffle/plugin.cpp @@ -93,9 +93,14 @@ return m_metaData; } +bool Plugin::hasRequiredExecutables() const +{ + return findExecutables(readOnlyExecutables()); +} + bool Plugin::isValid() const { - return isEnabled() && m_metaData.isValid() && findExecutables(readOnlyExecutables()); + return isEnabled() && m_metaData.isValid() && hasRequiredExecutables(); } bool Plugin::findExecutables(const QStringList &executables) diff --git a/kerfuffle/pluginmanager.cpp b/kerfuffle/pluginmanager.cpp --- a/kerfuffle/pluginmanager.cpp +++ b/kerfuffle/pluginmanager.cpp @@ -26,6 +26,8 @@ */ #include "pluginmanager.h" +#include "ark_debug.h" +#include "settings.h" #include #include @@ -195,12 +197,6 @@ void PluginManager::loadPlugins() { const QVector plugins = KPluginLoader::findPlugins(QStringLiteral("kerfuffle")); - // This class might be used from executables other than ark (e.g. the tests), - // so we need to specify the name of the config file. - // TODO: once we have a GUI in the settings dialog, - // use this group to write whether a plugin gets disabled. - const KConfigGroup conf(KSharedConfig::openConfig(QStringLiteral("arkrc")), "EnabledPlugins"); - QSet addedPlugins; foreach (const KPluginMetaData &metaData, plugins) { const auto pluginId = metaData.pluginId(); @@ -210,7 +206,7 @@ } Plugin *plugin = new Plugin(this, metaData); - plugin->setEnabled(conf.readEntry(pluginId, true)); + plugin->setEnabled(!ArkSettings::disabledPlugins().contains(pluginId)); addedPlugins << pluginId; m_plugins << plugin; } diff --git a/kerfuffle/pluginsettingspage.h b/kerfuffle/pluginsettingspage.h new file mode 100644 --- /dev/null +++ b/kerfuffle/pluginsettingspage.h @@ -0,0 +1,59 @@ +/* + * ark -- archiver for the KDE project + * + * Copyright (C) 2016 Elvis Angelaccio + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PLUGINSETTINGSPAGE_H +#define PLUGINSETTINGSPAGE_H + +#include "settingspage.h" +#include "pluginmanager.h" +#include "ui_pluginsettingspage.h" + +class QTreeWidgetItem; + +namespace Kerfuffle +{ +class KERFUFFLE_EXPORT PluginSettingsPage : public SettingsPage, public Ui::PluginSettingsPage +{ + Q_OBJECT + +public: + explicit PluginSettingsPage(QWidget *parent = Q_NULLPTR, const QString &name = QString(), const QString &iconName = QString()); + +public slots: + void slotSettingsChanged() Q_DECL_OVERRIDE; + void slotDefaultsButtonClicked() Q_DECL_OVERRIDE; + +private slots: + void slotItemChanged(QTreeWidgetItem *item); + +private: + QStringList m_toBeDisabled; // List of plugins that will be disabled upon clicking the Apply button. + PluginManager m_pluginManager; +}; +} + +#endif diff --git a/kerfuffle/pluginsettingspage.cpp b/kerfuffle/pluginsettingspage.cpp new file mode 100644 --- /dev/null +++ b/kerfuffle/pluginsettingspage.cpp @@ -0,0 +1,108 @@ +/* + * ark -- archiver for the KDE project + * + * Copyright (C) 2016 Elvis Angelaccio + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "pluginsettingspage.h" +#include "ark_debug.h" + +#include + +#include + +namespace Kerfuffle +{ + +PluginSettingsPage::PluginSettingsPage(QWidget *parent, const QString &name, const QString &iconName) + : SettingsPage(parent, name, iconName) +{ + setupUi(this); + + foreach (const auto plugin, m_pluginManager.installedPlugins()) { + const auto metaData = plugin->metaData(); + auto item = new QTreeWidgetItem(kcfg_disabledPlugins); + item->setData(0, Qt::UserRole, QVariant::fromValue(plugin)); + item->setText(0, metaData.name()); + item->setText(1, metaData.description()); + item->setCheckState(0, plugin->isEnabled() ? Qt::Checked : Qt::Unchecked); + if (!plugin->isEnabled()) { + m_toBeDisabled << metaData.pluginId(); + } + if (!plugin->hasRequiredExecutables()) { + item->setDisabled(true); + for (int i : {0, 1}) { + item->setToolTip(i, i18n("The plugin cannot be used because one or more required executables are missing. Check your installation.")); + } + } + } + + kcfg_disabledPlugins->resizeColumnToContents(0); + connect(kcfg_disabledPlugins, &QTreeWidget::itemChanged, this, &PluginSettingsPage::slotItemChanged); + + // Set the custom property that KConfigDialogManager will use to update the settings. + kcfg_disabledPlugins->setProperty("kcfg_property", QByteArray("disabledPlugins")); + // Tell KConfigDialogManager to monitor the itemChanged signal for a QTreeWidget instance in the dialog. + KConfigDialogManager::changedMap()->insert(QString::fromLatin1(QTreeWidget::staticMetaObject.className()), + SIGNAL(itemChanged(QTreeWidgetItem*,int))); +} + +void PluginSettingsPage::slotSettingsChanged() +{ + m_toBeDisabled.clear(); +} + +void PluginSettingsPage::slotDefaultsButtonClicked() +{ + // KConfigDialogManager doesn't know how to reset the QTreeWidget, we need to do it manually. + QTreeWidgetItemIterator iterator(kcfg_disabledPlugins); + while (*iterator) { + auto item = *iterator; + // By default every plugin is enabled. + item->setCheckState(0, Qt::Checked); + iterator++; + } +} + +void PluginSettingsPage::slotItemChanged(QTreeWidgetItem *item) +{ + auto plugin = item->data(0, Qt::UserRole).value(); + if (!plugin) { + return; + } + + const auto pluginId = plugin->metaData().pluginId(); + plugin->setEnabled(item->checkState(0) == Qt::Checked); + // If unchecked, add to the list of plugins that will be disabled. + m_toBeDisabled.removeAll(pluginId); + if (!plugin->isEnabled()) { + m_toBeDisabled << pluginId; + } + // Enable the Apply button by setting the property. + qCDebug(ARK) << "Going to disable the following plugins:" << m_toBeDisabled; + kcfg_disabledPlugins->setProperty("disabledPlugins", m_toBeDisabled); +} + +} + diff --git a/kerfuffle/pluginsettingspage.ui b/kerfuffle/pluginsettingspage.ui new file mode 100644 --- /dev/null +++ b/kerfuffle/pluginsettingspage.ui @@ -0,0 +1,38 @@ + + + PluginSettingsPage + + + + 0 + 0 + 547 + 487 + + + + + + + false + + + 2 + + + + Name + + + + + Description + + + + + + + + + diff --git a/part/part.cpp b/part/part.cpp --- a/part/part.cpp +++ b/part/part.cpp @@ -40,6 +40,7 @@ #include "settings.h" #include "previewsettingspage.h" #include "propertiesdialog.h" +#include "pluginsettingspage.h" #include "pluginmanager.h" #include @@ -797,6 +798,7 @@ QList pages; pages.append(new GeneralSettingsPage(parent, i18nc("@title:tab", "General Settings"), QStringLiteral("go-home"))); pages.append(new ExtractionSettingsPage(parent, i18nc("@title:tab", "Extraction Settings"), QStringLiteral("archive-extract"))); + pages.append(new PluginSettingsPage(parent, i18nc("@title:tab", "Plugin Settings"), QStringLiteral("plugins"))); pages.append(new PreviewSettingsPage(parent, i18nc("@title:tab", "Preview Settings"), QStringLiteral("document-preview-archive"))); return pages;