File indexing completed on 2025-01-26 05:09:00

0001 /*
0002     SPDX-FileCopyrightText: 2009 Alan Alpert <alan.alpert@nokia.com>
0003     SPDX-FileCopyrightText: 2010 Ménard Alexis <menard@kde.org>
0004     SPDX-FileCopyrightText: 2010 Marco Martin <mart@kde.org>
0005     SPDX-FileCopyrightText: 2013 Sebastian Kügler <sebas@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "datasource.h"
0011 #include <QAbstractItemModel>
0012 
0013 namespace Plasma5Support
0014 {
0015 DataSource::DataSource(QObject *parent)
0016     : QObject(parent)
0017     , m_ready(false)
0018     , m_interval(0)
0019     , m_intervalAlignment(Plasma5Support::Types::NoAlignment)
0020 {
0021     m_models = new QQmlPropertyMap(this);
0022     m_data = new QQmlPropertyMap(this);
0023     setObjectName(QStringLiteral("DataSource"));
0024 }
0025 
0026 void DataSource::classBegin()
0027 {
0028 }
0029 
0030 void DataSource::componentComplete()
0031 {
0032     m_ready = true;
0033     setupData();
0034 }
0035 
0036 void DataSource::setConnectedSources(const QStringList &sources)
0037 {
0038     bool sourcesChanged = false;
0039     for (const QString &source : sources) {
0040         if (!m_connectedSources.contains(source)) {
0041             sourcesChanged = true;
0042             if (m_dataEngine) {
0043                 m_connectedSources.append(source);
0044                 m_dataEngine->connectSource(source, this, m_interval, m_intervalAlignment);
0045                 Q_EMIT sourceConnected(source);
0046             }
0047         }
0048     }
0049 
0050     for (const QString &source : std::as_const(m_connectedSources)) {
0051         if (!sources.contains(source)) {
0052             m_data->clear(source);
0053             sourcesChanged = true;
0054             if (m_dataEngine) {
0055                 m_dataEngine->disconnectSource(source, this);
0056                 Q_EMIT sourceDisconnected(source);
0057             }
0058         }
0059     }
0060 
0061     if (sourcesChanged) {
0062         m_connectedSources = sources;
0063         Q_EMIT connectedSourcesChanged();
0064     }
0065 }
0066 
0067 void DataSource::setEngine(const QString &e)
0068 {
0069     if (e == m_engine) {
0070         return;
0071     }
0072 
0073     m_engine = e;
0074 
0075     if (m_engine.isEmpty()) {
0076         Q_EMIT engineChanged();
0077         return;
0078     }
0079 
0080     m_dataEngineConsumer.reset(new Plasma5Support::DataEngineConsumer());
0081     Plasma5Support::DataEngine *engine = dataEngine(m_engine);
0082     if (!engine) {
0083         qWarning() << "DataEngine" << m_engine << "not found";
0084         Q_EMIT engineChanged();
0085         return;
0086     }
0087 
0088     if (m_dataEngine) {
0089         m_dataEngine->disconnect(this);
0090         // Deleting the consumer triggers the reference counting
0091         m_dataEngineConsumer.reset();
0092     }
0093 
0094     /*
0095      * It is due little explanation why this is a queued connection:
0096      * If sourceAdded arrives immediately, in the case we have a datamodel
0097      * with items at source level we connect too soon (before setData for
0098      * all roles is done), having a dataupdated in the datamodel with only
0099      * the first role, killing off the other roles.
0100      * Besides causing a model reset more, unfortunately setRoleNames can be done a single time, so is not possible adding new roles after the
0101      * first setRoleNames() is called.
0102      * This fixes engines that have 1 item per source like the
0103      * recommendations engine.
0104      */
0105     m_dataEngine = engine;
0106     connect(m_dataEngine, &DataEngine::sourceAdded, this, &DataSource::updateSources, Qt::QueuedConnection);
0107     connect(m_dataEngine, &DataEngine::sourceRemoved, this, &DataSource::updateSources);
0108 
0109     connect(m_dataEngine, &DataEngine::sourceAdded, this, &DataSource::sourceAdded, Qt::QueuedConnection);
0110     connect(m_dataEngine, &DataEngine::sourceRemoved, this, &DataSource::removeSource);
0111     connect(m_dataEngine, &DataEngine::sourceRemoved, this, &DataSource::sourceRemoved);
0112 
0113     updateSources();
0114 
0115     Q_EMIT engineChanged();
0116 }
0117 
0118 void DataSource::setInterval(const int interval)
0119 {
0120     if (interval == m_interval) {
0121         return;
0122     }
0123 
0124     m_interval = interval;
0125     setupData();
0126     Q_EMIT intervalChanged();
0127 }
0128 
0129 void DataSource::setIntervalAlignment(Plasma5Support::Types::IntervalAlignment intervalAlignment)
0130 {
0131     if (intervalAlignment == m_intervalAlignment) {
0132         return;
0133     }
0134 
0135     m_intervalAlignment = intervalAlignment;
0136     setupData();
0137     Q_EMIT intervalAlignmentChanged();
0138 }
0139 
0140 void DataSource::setupData()
0141 {
0142     if (!m_ready) {
0143         return;
0144     }
0145 
0146     //     qDebug() << " loading engine " << m_engine;
0147     // FIXME: should all services be deleted just because we're changing the interval, etc?
0148     qDeleteAll(m_services);
0149     m_services.clear();
0150 
0151     for (const QString &source : std::as_const(m_connectedSources)) {
0152         m_dataEngine->connectSource(source, this, m_interval, m_intervalAlignment);
0153         Q_EMIT sourceConnected(source);
0154     }
0155 }
0156 
0157 void DataSource::dataUpdated(const QString &sourceName, const Plasma5Support::DataEngine::Data &data)
0158 {
0159     // it can arrive also data we don't explicitly connected a source
0160     if (m_connectedSources.contains(sourceName)) {
0161         m_data->insert(sourceName, data);
0162         Q_EMIT dataChanged();
0163         Q_EMIT newData(sourceName, data);
0164     } else if (m_dataEngine) {
0165         m_dataEngine->disconnectSource(sourceName, this);
0166     }
0167 }
0168 
0169 void DataSource::modelChanged(const QString &sourceName, QAbstractItemModel *model)
0170 {
0171     if (!model) {
0172         m_models->clear(sourceName);
0173         return;
0174     }
0175 
0176     m_models->insert(sourceName, QVariant::fromValue(model));
0177     // FIXME: this will break in the case a second model is set
0178     connect(model, &QObject::destroyed, m_models, [this, sourceName]() {
0179         m_models->clear(sourceName);
0180     });
0181 }
0182 
0183 void DataSource::removeSource(const QString &source)
0184 {
0185     m_data->clear(source);
0186     m_models->clear(source);
0187 
0188     // TODO: emit those signals as last thing
0189     if (m_connectedSources.contains(source)) {
0190         m_connectedSources.removeAll(source);
0191         Q_EMIT sourceDisconnected(source);
0192         Q_EMIT connectedSourcesChanged();
0193     }
0194 
0195     if (m_dataEngine) {
0196         QHash<QString, Plasma5Support::Service *>::iterator it = m_services.find(source);
0197         if (it != m_services.end()) {
0198             delete it.value();
0199             m_services.erase(it);
0200         }
0201     }
0202 }
0203 
0204 QObject *DataSource::serviceForSource(const QString &source)
0205 {
0206     if (!m_services.contains(source)) {
0207         Plasma5Support::Service *service = m_dataEngine->serviceForSource(source);
0208         if (!service) {
0209             return nullptr;
0210         }
0211         m_services[source] = service;
0212     }
0213 
0214     return m_services.value(source);
0215 }
0216 
0217 void DataSource::connectSource(const QString &source)
0218 {
0219     if (m_connectedSources.contains(source)) {
0220         return;
0221     }
0222 
0223     m_connectedSources.append(source);
0224     if (m_dataEngine) {
0225         m_dataEngine->connectSource(source, this, m_interval, m_intervalAlignment);
0226         Q_EMIT sourceConnected(source);
0227         Q_EMIT connectedSourcesChanged();
0228     }
0229 }
0230 
0231 void DataSource::disconnectSource(const QString &source)
0232 {
0233     if (m_dataEngine && m_connectedSources.contains(source)) {
0234         m_connectedSources.removeAll(source);
0235         m_dataEngine->disconnectSource(source, this);
0236         Q_EMIT sourceDisconnected(source);
0237         Q_EMIT connectedSourcesChanged();
0238     }
0239 }
0240 
0241 void DataSource::updateSources()
0242 {
0243     QStringList sources;
0244     if (m_dataEngine) {
0245         sources = m_dataEngine->sources();
0246     }
0247 
0248     if (sources != m_sources) {
0249         m_sources = sources;
0250         Q_EMIT sourcesChanged();
0251     }
0252 }
0253 
0254 }
0255 
0256 #include "moc_datasource.cpp"