diff --git a/kerfuffle/CMakeLists.txt b/kerfuffle/CMakeLists.txt --- a/kerfuffle/CMakeLists.txt +++ b/kerfuffle/CMakeLists.txt @@ -16,6 +16,7 @@ cliinterface.cpp mimetypes.cpp plugin.cpp + pluginmanager.cpp ) kconfig_add_kcfg_files(kerfuffle_SRCS settings.kcfgc) diff --git a/kerfuffle/pluginmanager.h b/kerfuffle/pluginmanager.h new file mode 100644 --- /dev/null +++ b/kerfuffle/pluginmanager.h @@ -0,0 +1,128 @@ +/* + * 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 PLUGINMANAGER_H +#define PLUGINMANAGER_H + +#include "plugin.h" + +#include + +namespace Kerfuffle +{ + +class KERFUFFLE_EXPORT PluginManager : public QObject +{ + Q_OBJECT + +public: + explicit PluginManager(QObject *parent = Q_NULLPTR); + + /** + * @return The list of all installed plugins. + * An installed plugin is not necessarily available to the app. + * The user could have disabled it from the settings, or the needed executables could not be found. + */ + QVector installedPlugins() const; + + /** + * @return The list of plugins ready to be used. Includes read-only and read-write ones. + */ + QVector availablePlugins() const; + + /** + * @return The list of read-write plugins ready to be used. + */ + QVector availableWritePlugins() const; + + /** + * @return The list of plugins enabled by the user in the settings dialog. + */ + QVector enabledPlugins() const; + + /** + * @return The list of preferred plugins for the given @p mimeType, among all the available ones. + * The list is sorted according to the plugins priority. + * If no plugin is available, returns an empty list. + */ + QVector preferredPluginsFor(const QMimeType &mimeType) const; + + /** + * @return The list of preferred read-write plugins for the given @p mimeType, among all the available ones. + * The list is sorted according to the plugins priority. + * If no read-write plugin is available, returns an empty list. + */ + QVector preferredWritePluginsFor(const QMimeType &mimeType) const; + + /** + * @return The preferred plugin for the given @p mimeType, among all the available ones. + * If no plugin is available, returns an invalid plugin. + */ + Plugin *preferredPluginFor(const QMimeType &mimeType) const; + + /** + * @return The preferred read-write plugin for the given @p mimeType, among all the available ones. + * If no read-write plugin is available, returns an invalid plugin. + */ + Plugin *preferredWritePluginFor(const QMimeType &mimeType) const; + + /** + * @return The list of all mimetypes that Ark can open, sorted according to their comment. + */ + QStringList supportedMimeTypes() const; + + /** + * @return The list of all read-write mimetypes supported by Ark, sorted according to their comment. + */ + QStringList supportedWriteMimeTypes() const; + + /** + * @return The given list of @p plugins filtered by @p mimeType. + */ + static QVector filterBy(const QVector &plugins, const QMimeType &mimeType); + +private: + + void loadPlugins(); + + /** + * @param readWrite whether to return only the read-write plugins. + * @return The list of preferred plugins for @p mimeType among the available ones, sorted by priority. + */ + QVector preferredPluginsFor(const QMimeType &mimeType, bool readWrite) const; + + /** + * @return A list with the given @p mimeTypes, alphabetically sorted according to their comment. + */ + static QStringList sortByComment(const QSet &mimeTypes); + + QVector m_plugins; +}; + +} + +#endif diff --git a/kerfuffle/pluginmanager.cpp b/kerfuffle/pluginmanager.cpp new file mode 100644 --- /dev/null +++ b/kerfuffle/pluginmanager.cpp @@ -0,0 +1,196 @@ +/* + * 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 "pluginmanager.h" + +#include +#include +#include + +#include +#include + +#include + +namespace Kerfuffle +{ + +PluginManager::PluginManager(QObject *parent) : QObject(parent) +{ + loadPlugins(); +} + +QVector PluginManager::installedPlugins() const +{ + return m_plugins; +} + +QVector PluginManager::availablePlugins() const +{ + QVector availablePlugins; + foreach (Plugin *plugin, m_plugins) { + if (plugin->isValid()) { + availablePlugins << plugin; + } + } + + return availablePlugins; +} + +QVector PluginManager::availableWritePlugins() const +{ + QVector availableWritePlugins; + foreach (Plugin *plugin, availablePlugins()) { + if (plugin->isReadWrite()) { + availableWritePlugins << plugin; + } + } + + return availableWritePlugins; +} + +QVector PluginManager::enabledPlugins() const +{ + QVector enabledPlugins; + foreach (Plugin *plugin, m_plugins) { + if (plugin->isEnabled()) { + enabledPlugins << plugin; + } + } + + return enabledPlugins; +} + +QVector PluginManager::preferredPluginsFor(const QMimeType &mimeType) const +{ + return preferredPluginsFor(mimeType, false); +} + +QVector PluginManager::preferredWritePluginsFor(const QMimeType &mimeType) const +{ + return preferredPluginsFor(mimeType, true); +} + +Plugin *PluginManager::preferredPluginFor(const QMimeType &mimeType) const +{ + const QVector preferredPlugins = preferredPluginsFor(mimeType); + return preferredPlugins.isEmpty() ? new Plugin() : preferredPlugins.first(); +} + +Plugin *PluginManager::preferredWritePluginFor(const QMimeType &mimeType) const +{ + const QVector preferredWritePlugins = preferredWritePluginsFor(mimeType); + return preferredWritePlugins.isEmpty() ? new Plugin() : preferredWritePlugins.first(); +} + +QStringList PluginManager::supportedMimeTypes() const +{ + QSet supported; + foreach (Plugin *plugin, availablePlugins()) { + supported += plugin->metaData().mimeTypes().toSet(); + } + + // Remove entry for lrzipped tar if lrzip executable not found in path. + if (QStandardPaths::findExecutable(QStringLiteral("lrzip")).isEmpty()) { + supported.remove(QStringLiteral("application/x-lrzip-compressed-tar")); + } + + return sortByComment(supported); +} + +QStringList PluginManager::supportedWriteMimeTypes() const +{ + QSet supported; + foreach (Plugin *plugin, availableWritePlugins()) { + supported += plugin->metaData().mimeTypes().toSet(); + } + + // Remove entry for lrzipped tar if lrzip executable not found in path. + if (QStandardPaths::findExecutable(QStringLiteral("lrzip")).isEmpty()) { + supported.remove(QStringLiteral("application/x-lrzip-compressed-tar")); + } + + return sortByComment(supported); +} + +QVector PluginManager::filterBy(const QVector &plugins, const QMimeType &mimeType) +{ + QVector filteredPlugins; + foreach (Plugin *plugin, plugins) { + if (plugin->metaData().mimeTypes().contains(mimeType.name())) { + filteredPlugins << plugin; + } + } + + return filteredPlugins; +} + +void PluginManager::loadPlugins() +{ + const QVector plugins = KPluginLoader::findPlugins(QStringLiteral("kerfuffle")); + // 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(), "EnabledPlugins"); + + foreach (const KPluginMetaData &metaData, plugins) { + Plugin *plugin = new Plugin(this, metaData); + plugin->setEnabled(conf.readEntry(metaData.pluginId(), true)); + m_plugins << plugin; + } +} + +QVector PluginManager::preferredPluginsFor(const QMimeType &mimeType, bool readWrite) const +{ + QVector preferredPlugins = filterBy((readWrite ? availableWritePlugins() : availablePlugins()), mimeType); + + std::sort(preferredPlugins.begin(), preferredPlugins.end(), [](Plugin* p1, Plugin* p2) { + return p1->priority() > p2->priority(); + }); + + return preferredPlugins; +} + +QStringList PluginManager::sortByComment(const QSet &mimeTypes) +{ + QMap map; + + // Initialize the QMap to sort by comment. + foreach (const QString &mimeType, mimeTypes) { + QMimeType mime(QMimeDatabase().mimeTypeForName(mimeType)); + map[mime.comment().toLower()] = mime.name(); + } + + // Convert to sorted QStringList. + QStringList sortedMimeTypes; + foreach (const QString &value, map) { + sortedMimeTypes << value; + } + + return sortedMimeTypes; +} + +}