File indexing completed on 2024-05-12 05:37:12

0001 /*
0002     SPDX-FileCopyrightText: 2015 Martin Klapetek <mklapetek@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "eventpluginsmanager.h"
0008 
0009 #include <QAbstractListModel>
0010 #include <QCoreApplication>
0011 #include <QDebug>
0012 #include <QDir>
0013 #include <QJsonObject>
0014 #include <QPluginLoader>
0015 
0016 #include <KPluginMetaData>
0017 
0018 class EventPluginsManagerPrivate
0019 {
0020 public:
0021     explicit EventPluginsManagerPrivate();
0022     ~EventPluginsManagerPrivate();
0023 
0024     friend class EventPluginsModel;
0025     struct PluginData {
0026         QString name;
0027         QString desc;
0028         QString icon;
0029         QString configUi;
0030     };
0031 
0032     std::unique_ptr<EventPluginsModel> model;
0033     QList<CalendarEvents::CalendarEventsPlugin *> plugins;
0034     QMap<QString, PluginData> availablePlugins;
0035     QStringList enabledPlugins;
0036 };
0037 
0038 class EventPluginsModel : public QAbstractListModel
0039 {
0040     Q_OBJECT
0041 public:
0042     EventPluginsModel(EventPluginsManagerPrivate *d)
0043         : d(d)
0044         , m_roles(QAbstractListModel::roleNames())
0045     {
0046         m_roles.insert(Qt::EditRole, QByteArrayLiteral("checked"));
0047         m_roles.insert(Qt::UserRole, QByteArrayLiteral("configUi"));
0048         m_roles.insert(Qt::UserRole + 1, QByteArrayLiteral("pluginId"));
0049     }
0050 
0051     // make these two available to the manager
0052     void beginResetModel()
0053     {
0054         QAbstractListModel::beginResetModel();
0055     }
0056 
0057     void endResetModel()
0058     {
0059         QAbstractListModel::endResetModel();
0060     }
0061 
0062     QHash<int, QByteArray> roleNames() const override
0063     {
0064         return m_roles;
0065     }
0066 
0067     Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const override
0068     {
0069         Q_UNUSED(parent);
0070         return d->availablePlugins.size();
0071     }
0072 
0073     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
0074     {
0075         if (!index.isValid() || !d) {
0076             return QVariant();
0077         }
0078 
0079         const auto it = std::next(d->availablePlugins.cbegin(), index.row());
0080         const QString currentPlugin = it.key();
0081         const EventPluginsManagerPrivate::PluginData metadata = it.value();
0082 
0083         switch (role) {
0084         case Qt::DisplayRole:
0085             return metadata.name;
0086         case Qt::ToolTipRole:
0087             return metadata.desc;
0088         case Qt::DecorationRole:
0089             return metadata.icon;
0090         case Qt::UserRole: {
0091             return metadata.configUi;
0092         }
0093         case Qt::UserRole + 1:
0094             return currentPlugin;
0095         case Qt::EditRole:
0096             return d->enabledPlugins.contains(currentPlugin);
0097         }
0098 
0099         return QVariant();
0100     }
0101 
0102     bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override
0103     {
0104         if (role != Qt::EditRole || !index.isValid()) {
0105             return false;
0106         }
0107 
0108         bool enabled = value.toBool();
0109         const QString pluginId = d->availablePlugins.keys().at(index.row());
0110 
0111         if (enabled) {
0112             if (!d->enabledPlugins.contains(pluginId)) {
0113                 d->enabledPlugins << pluginId;
0114             }
0115         } else {
0116             d->enabledPlugins.removeOne(pluginId);
0117         }
0118 
0119         Q_EMIT dataChanged(index, index);
0120 
0121         return true;
0122     }
0123 
0124     Q_INVOKABLE QVariant get(int row, const QByteArray &role)
0125     {
0126         return data(createIndex(row, 0), roleNames().key(role));
0127     }
0128 
0129 private:
0130     EventPluginsManagerPrivate *d;
0131     QHash<int, QByteArray> m_roles;
0132 };
0133 
0134 EventPluginsManagerPrivate::EventPluginsManagerPrivate()
0135     : model(std::make_unique<EventPluginsModel>(this))
0136 {
0137     const auto plugins = KPluginMetaData::findPlugins(QStringLiteral("plasmacalendarplugins"));
0138     for (const KPluginMetaData &plugin : plugins) {
0139         const QString prefix = plugin.fileName().left(plugin.fileName().lastIndexOf(QLatin1Char('/')));
0140         const QString configName = plugin.value(QStringLiteral("X-KDE-PlasmaCalendar-ConfigUi"));
0141 
0142         availablePlugins.insert(plugin.pluginId(), {plugin.name(), plugin.description(), plugin.iconName(), prefix + QLatin1Char('/') + configName});
0143     }
0144 }
0145 
0146 EventPluginsManagerPrivate::~EventPluginsManagerPrivate()
0147 {
0148     qDeleteAll(plugins);
0149 }
0150 
0151 EventPluginsManager::EventPluginsManager(QObject *parent)
0152     : QObject(parent)
0153     , d(new EventPluginsManagerPrivate)
0154 {
0155 }
0156 
0157 EventPluginsManager::~EventPluginsManager()
0158 {
0159     delete d;
0160 }
0161 
0162 void EventPluginsManager::populateEnabledPluginsList(const QStringList &pluginsList)
0163 {
0164     d->model->beginResetModel();
0165     d->enabledPlugins = pluginsList;
0166     d->model->endResetModel();
0167 }
0168 
0169 void EventPluginsManager::setEnabledPlugins(QStringList &pluginsList)
0170 {
0171     d->model->beginResetModel();
0172     d->enabledPlugins = pluginsList;
0173 
0174     // Remove all already loaded plugins from the pluginsList
0175     // and unload those plugins that are not in the pluginsList
0176     auto i = d->plugins.begin();
0177     while (i != d->plugins.end()) {
0178         const QString pluginId = (*i)->property("pluginId").toString();
0179         if (pluginsList.contains(pluginId)) {
0180             pluginsList.removeAll(pluginId);
0181             ++i;
0182         } else {
0183             (*i)->deleteLater();
0184             i = d->plugins.erase(i);
0185         }
0186     }
0187 
0188     // Now load all the plugins left in pluginsList
0189     for (const QString &pluginId : std::as_const(pluginsList)) {
0190         loadPlugin(pluginId);
0191     }
0192 
0193     d->model->endResetModel();
0194     Q_EMIT pluginsChanged();
0195 }
0196 
0197 QStringList EventPluginsManager::enabledPlugins() const
0198 {
0199     return d->enabledPlugins;
0200 }
0201 
0202 void EventPluginsManager::loadPlugin(const QString &pluginId)
0203 {
0204     QPluginLoader loader("plasmacalendarplugins/" + QDir::cleanPath(pluginId));
0205 
0206     if (!loader.load()) {
0207         qWarning() << "Could not create Plasma Calendar Plugin: " << pluginId;
0208         qWarning() << loader.errorString();
0209         return;
0210     }
0211 
0212     QObject *obj = loader.instance();
0213     if (obj) {
0214         CalendarEvents::CalendarEventsPlugin *eventsPlugin = qobject_cast<CalendarEvents::CalendarEventsPlugin *>(obj);
0215         if (eventsPlugin) {
0216             qDebug() << "Loading Calendar plugin" << eventsPlugin;
0217             eventsPlugin->setProperty("pluginId", pluginId);
0218             d->plugins << eventsPlugin;
0219 
0220             // Connect the relay signals
0221             connect(eventsPlugin, &CalendarEvents::CalendarEventsPlugin::dataReady, this, &EventPluginsManager::dataReady);
0222             connect(eventsPlugin, &CalendarEvents::CalendarEventsPlugin::eventModified, this, &EventPluginsManager::eventModified);
0223             connect(eventsPlugin, &CalendarEvents::CalendarEventsPlugin::eventRemoved, this, &EventPluginsManager::eventRemoved);
0224             connect(eventsPlugin, &CalendarEvents::CalendarEventsPlugin::alternateCalendarDateReady, this, &EventPluginsManager::alternateCalendarDateReady);
0225             connect(eventsPlugin, &CalendarEvents::CalendarEventsPlugin::subLabelReady, this, &EventPluginsManager::subLabelReady);
0226         } else {
0227             // not our/valid plugin, so unload it
0228             loader.unload();
0229         }
0230     } else {
0231         loader.unload();
0232     }
0233 }
0234 
0235 QList<CalendarEvents::CalendarEventsPlugin *> EventPluginsManager::plugins() const
0236 {
0237     return d->plugins;
0238 }
0239 
0240 QAbstractListModel *EventPluginsManager::pluginsModel() const
0241 {
0242     return d->model.get();
0243 }
0244 
0245 #include "eventpluginsmanager.moc"