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"