massive change in DataSource:

* possible to connect multiple sources
* use a normal QMap instead of the quirky qdeclarativepropertymap
* DataModel can be connected to multiple sources as well
* possible to use them with dataengines such as activities and tasks where the first level keys are the "roles" themselves

(all examples in playground have to be adapted)

svn path=/trunk/KDE/kdebase/runtime/; revision=1194216
This commit is contained in:
Marco Martin 2010-11-08 10:27:36 +00:00
parent 5cc73ecf16
commit befceb8dee
4 changed files with 243 additions and 137 deletions

View File

@ -124,26 +124,43 @@ DataModel::~DataModel()
{ {
} }
int DataModel::countItems() const
{
int count = 0;
foreach (const QVector<QVariant> &v, m_items) {
count += v.count();
}
return count;
}
void DataModel::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data) void DataModel::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
{ {
Q_UNUSED(sourceName); if (!m_keyRoleFilter.isEmpty()) {
//a key that matches the one we want exists and is a list of DataEngine::Data
if (data.contains(m_key) && data.value(m_key).canConvert<QVariantList>()) { if (data.contains(m_keyRoleFilter) && data.value(m_keyRoleFilter).canConvert<QVariantList>()) {
setItems(data.value(m_key).value<QVariantList>()); setItems(sourceName, data.value(m_keyRoleFilter).value<QVariantList>());
} else { //try to match the key we want with a regular expression if set
QRegExp regExp(m_key); } else {
if (!regExp.isValid()) { QRegExp regExp(m_keyRoleFilter);
return; if (regExp.isValid()) {
} QHash<QString, QVariant>::const_iterator i;
QVariantList list;
QHash<QString, QVariant>::const_iterator i; for (i = data.constBegin(); i != data.constEnd(); ++i) {
QVariantList list; if (regExp.exactMatch(i.key())) {
for (i = data.constBegin(); i != data.constEnd(); ++i) { list.append(i.value());
if (regExp.exactMatch(i.key())) { }
list.append(i.value()); }
setItems(sourceName, list);
} }
} }
setItems(list); //an item is represented by a source: keys are roles m_roleLevel == FirstLevel
} else {
QVariantList list;
foreach (Plasma::DataEngine::Data data, m_dataSource->data()) {
list.append(data);
}
setItems(QString(), list);
} }
} }
@ -169,26 +186,26 @@ QObject *DataModel::dataSource() const
return m_dataSource; return m_dataSource;
} }
void DataModel::setKey(const QString key) void DataModel::setKeyRoleFilter(const QString key)
{ {
if (m_key == key) { if (m_keyRoleFilter == key) {
return; return;
} }
m_key = key; m_keyRoleFilter = key;
} }
QString DataModel::key() const QString DataModel::keyRoleFilter() const
{ {
return m_key; return m_keyRoleFilter;
} }
void DataModel::setItems(const QVariantList &list) void DataModel::setItems(const QString &sourceName, const QVariantList &list)
{ {
emit modelAboutToBeReset(); emit modelAboutToBeReset();
//convert to vector, so data() will be O(1) //convert to vector, so data() will be O(1)
m_items = list.toVector(); m_items[sourceName] = list.toVector();
if (!list.isEmpty()) { if (!list.isEmpty()) {
int role = Qt::UserRole; int role = Qt::UserRole;
@ -220,14 +237,29 @@ void DataModel::setItems(const QVariantList &list)
QVariant DataModel::data(const QModelIndex &index, int role) const QVariant DataModel::data(const QModelIndex &index, int role) const
{ {
if (!index.isValid() || index.column() > 0 || if (!index.isValid() || index.column() > 0 ||
index.row() < 0 || index.row() >= m_items.count()){ index.row() < 0 || index.row() >= countItems()){
return QVariant(); return QVariant();
} }
if (m_items.value(index.row()).canConvert<QVariantHash>()) { int count = 0;
return m_items.value(index.row()).value<QVariantHash>().value(m_roleNames.value(role)); int actualRow = 0;
QString source;
QMap<QString, QVector<QVariant> >::const_iterator i;
for (i = m_items.constBegin(); i != m_items.constEnd(); ++i) {
const int oldCount = count;
count += i.value().count();
if (index.row() < count) {
source = i.key();
actualRow = index.row() - oldCount;
break;
}
}
if (m_items.value(source).value(actualRow).canConvert<QVariantHash>()) {
return m_items.value(source).value(actualRow).value<QVariantHash>().value(m_roleNames.value(role));
} else { } else {
return m_items.value(index.row()).value<QVariantMap>().value(m_roleNames.value(role)); return m_items.value(source).value(actualRow).value<QVariantMap>().value(m_roleNames.value(role));
} }
} }
@ -242,7 +274,7 @@ QVariant DataModel::headerData(int section, Qt::Orientation orientation, int rol
QModelIndex DataModel::index(int row, int column, const QModelIndex &parent) const QModelIndex DataModel::index(int row, int column, const QModelIndex &parent) const
{ {
if (parent.isValid() || column > 0 || row < 0 || row >= m_items.count()) { if (parent.isValid() || column > 0 || row < 0 || row >= countItems()) {
return QModelIndex(); return QModelIndex();
} }
@ -264,7 +296,7 @@ int DataModel::rowCount(const QModelIndex &parent) const
return 0; return 0;
} }
return m_items.count(); return countItems();
} }
int DataModel::columnCount(const QModelIndex &parent) const int DataModel::columnCount(const QModelIndex &parent) const

View File

@ -80,7 +80,7 @@ class DataModel : public QAbstractItemModel
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QObject *dataSource READ dataSource WRITE setDataSource) Q_PROPERTY(QObject *dataSource READ dataSource WRITE setDataSource)
Q_PROPERTY(QString key READ key WRITE setKey) Q_PROPERTY(QString keyRoleFilter READ keyRoleFilter WRITE setKeyRoleFilter)
public: public:
DataModel(QObject* parent=0); DataModel(QObject* parent=0);
@ -89,10 +89,8 @@ public:
void setDataSource(QObject *source); void setDataSource(QObject *source);
QObject *dataSource() const; QObject *dataSource() const;
void setKey(const QString key); void setKeyRoleFilter(const QString key);
QString key() const; QString keyRoleFilter() const;
void setItems(const QVariantList &list);
int roleNameToId(const QString &name); int roleNameToId(const QString &name);
@ -106,6 +104,10 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const; int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const;
protected:
void setItems(const QString &sourceName, const QVariantList &list);
inline int countItems() const;
Q_SIGNALS: Q_SIGNALS:
void modelAboutToBeReset(); void modelAboutToBeReset();
void modelReset(); void modelReset();
@ -115,8 +117,8 @@ private Q_SLOTS:
private: private:
DataSource *m_dataSource; DataSource *m_dataSource;
QString m_key; QString m_keyRoleFilter;
QVector<QVariant> m_items; QMap<QString, QVector<QVariant> > m_items;
QHash<int, QByteArray> m_roleNames; QHash<int, QByteArray> m_roleNames;
QHash<QString, int> m_roleIds; QHash<QString, int> m_roleIds;
}; };

View File

@ -37,91 +37,150 @@ DataSource::DataSource(QObject* parent)
{ {
setObjectName("DataSource"); setObjectName("DataSource");
m_data = new QDeclarativePropertyMap(this); // m_data = new QDeclarativePropertyMap(this);
connect(this, SIGNAL(engineChanged()), connect(this, SIGNAL(engineChanged()),
this, SLOT(setupData())); this, SLOT(setupData()));
connect(this, SIGNAL(sourceChanged()), connect(this, SIGNAL(connectedSourcesChanged()),
this, SLOT(setupData())); this, SLOT(setupData()));
connect(this, SIGNAL(intervalChanged()), connect(this, SIGNAL(intervalChanged()),
this, SLOT(setupData())); this, SLOT(setupData()));
} }
void DataSource::setSource(const QString &s) void DataSource::setConnectedSources(const QStringList &sources)
{ {
if (s == m_source) { foreach (const QString &source, sources) {
return; if (!m_connectedSources.contains(source)) {
m_newSources.append(source);
}
}
foreach (const QString &source, m_connectedSources) {
if (!m_connectedSources.contains(source)) {
m_oldSources.append(source);
}
} }
m_source = s; if (!m_newSources.isEmpty() || !m_oldSources.isEmpty()) {
emit sourceChanged(); m_connectedSources = sources;
m_changes |= SourcesChanged;
emit connectedSourcesChanged();
}
}
void DataSource::setEngine(const QString &e)
{
if (e == m_engine) {
return;
}
m_engine = e;
m_changes |= DataEngineChanged;
emit engineChanged();
} }
void DataSource::setupData() void DataSource::setupData()
{ {
if (/*m_source.isEmpty() ||*/ m_engine.isEmpty()) {
return; if (m_changes & DataEngineChanged) {
if (m_dataEngine) {
foreach (const QString &source, m_connectedSources) {
m_dataEngine->disconnectSource(source, this);
}
}
//FIXME: delete all?
m_services.clear();
m_dataEngine = dataEngine(m_engine);
if (!m_dataEngine) {
kWarning() << "DataEngine" << m_engine << "not found";
return;
}
connect(m_dataEngine, SIGNAL(sourceAdded(const QString&)), this, SIGNAL(allSourcesChanged()));
connect(m_dataEngine, SIGNAL(sourceRemoved(const QString&)), this, SIGNAL(allSourcesChanged()));
connect(m_dataEngine, SIGNAL(sourceAdded(const QString&)), this, SIGNAL(sourceAdded(const QString&)));
connect(m_dataEngine, SIGNAL(sourceRemoved(const QString&)), this, SLOT(removeSource(const QString&)));
if (!(m_changes & SourcesChanged)) {
foreach (const QString &source, m_connectedSources) {
m_dataEngine->connectSource(source, this);
}
}
} }
if (m_dataEngine) { if (m_changes & SourcesChanged) {
m_dataEngine->disconnectSource(m_connectedSource, this); if (m_dataEngine) {
m_dataEngine = 0; foreach (const QString &source, m_oldSources) {
m_keys.clear(); m_dataEngine->disconnectSource(source, this);
emit keysChanged(); }
foreach (const QString &source, m_newSources) {
m_dataEngine->connectSource(source, this);
}
m_oldSources.clear();
m_newSources.clear();
}
} }
m_changes = NoChange;
Plasma::DataEngine* de = dataEngine(m_engine);
if (!de) {
kWarning() << "DataEngine not found";
return;
}
de->connectSource(m_source, this, m_interval);
m_dataEngine = de;
m_connectedSource = m_source;
connect(de, SIGNAL(sourceAdded(constQString&)), this, SIGNAL(sourcesChanged()));
connect(de, SIGNAL(sourceRemoved(constQString&)), this, SIGNAL(sourcesChanged()));
} }
void DataSource::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data) void DataSource::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
{ {
Q_UNUSED(sourceName);//Only one source
QStringList newKeys; QStringList newKeys;
foreach (const QString &key, data.keys()) { m_data.insert(sourceName.toLatin1(), data);
// Properties in QML must start lowercase.
QString ourKey = key.toLower();
m_data->insert(ourKey.toLatin1(), data.value(key));
newKeys << ourKey;
}
if (newKeys != m_keys) {
//FIXME: pretty utterly inefficient
foreach (const QString &key, m_keys) {
if (!newKeys.contains(key)) {
m_data->insert(key.toLatin1(), QVariant());
}
}
emit keysChanged();
m_keys = newKeys;
}
emit dataChanged(); emit dataChanged();
emit newData(sourceName, data); emit newData(sourceName, data);
} }
Plasma::Service *DataSource::service() void DataSource::removeSource(const QString &source)
{ {
if (!m_service) { m_data.remove(source);
m_service = m_dataEngine->serviceForSource(m_source);
if (m_connectedSources.contains(source)) {
emit connectedSourcesChanged();
}
if (m_dataEngine) {
m_connectedSources.removeAll(source);
m_newSources.removeAll(source);
m_oldSources.removeAll(source);
//TODO: delete it?
m_services.remove(source);
emit connectedSourcesChanged();
}
}
QStringList DataSource::keysForSource(const QString &source) const
{
if (!m_data.contains(source)) {
return QStringList();
}
return m_data.value(source).keys();
}
Plasma::Service *DataSource::serviceForSource(const QString &source)
{
if (!m_services.contains(source)) {
m_services[source] = m_dataEngine->serviceForSource(source);
} }
return m_service; return m_services.value(source);
}
void DataSource::connectSource(const QString &source)
{
m_newSources.append(source);
m_connectedSources.append(source);
m_changes |= SourcesChanged;
emit connectedSourcesChanged();
}
void DataSource::disconnectSource(const QString &source)
{
m_oldSources.append(source);
m_connectedSources.removeAll(source);
m_changes |= SourcesChanged;
emit connectedSourcesChanged();
} }
} }

View File

@ -37,65 +37,78 @@ class QDeclarativePropertyMap;
namespace Plasma namespace Plasma
{ {
class DataEngine; class DataEngine;
class DataSource : public QObject, DataEngineConsumer class DataSource : public QObject, DataEngineConsumer
{ {
Q_OBJECT Q_OBJECT
public: public:
typedef QHash<QString, QVariant> Data; enum Change {
DataSource(QObject* parent=0); NoChange = 0,
DataEngineChanged = 1,
SourcesChanged = 2
};
Q_DECLARE_FLAGS(Changes, Change)
typedef QHash<QString, QVariant> Data;
typedef QMap<QString, Data> DataMap;
DataSource(QObject* parent=0);
Q_PROPERTY(bool valid READ valid) Q_PROPERTY(bool valid READ valid)
bool valid() const {return m_dataEngine != 0;} bool valid() const {return m_dataEngine != 0;}
Q_PROPERTY(int interval READ interval WRITE setInterval NOTIFY intervalChanged) Q_PROPERTY(int interval READ interval WRITE setInterval NOTIFY intervalChanged)
int interval() const {return m_interval;} int interval() const {return m_interval;}
void setInterval(int i) {if(i==m_interval) return; m_interval=i; emit intervalChanged();} void setInterval(int i) {if(i==m_interval) return; m_interval=i; emit intervalChanged();}
Q_PROPERTY(QString engine READ engine WRITE setEngine NOTIFY engineChanged) Q_PROPERTY(QString engine READ engine WRITE setEngine NOTIFY engineChanged)
QString engine() const {return m_engine;} QString engine() const {return m_engine;}
void setEngine(const QString &e) {if(e==m_engine) return; m_engine=e; emit engineChanged();} void setEngine(const QString &e);
Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(QStringList connectedSources READ connectedSources WRITE setConnectedSources NOTIFY connectedSourcesChanged)
QString source() const {return m_source;} QStringList connectedSources() const {return m_connectedSources;}
void setSource(const QString &s); void setConnectedSources(const QStringList &s);
Q_PROPERTY(QStringList keys READ keys NOTIFY keysChanged) Q_PROPERTY(QStringList sources READ sources NOTIFY sourcesChanged)
QStringList keys() const {return m_keys;} QStringList sources() const {if (m_dataEngine) return m_dataEngine->sources(); else return QStringList();}
Q_PROPERTY(QStringList allSources READ allSources NOTIFY sourcesChanged) Q_PROPERTY(DataMap data READ data NOTIFY dataChanged);
QStringList allSources() const {if (m_dataEngine) return m_dataEngine->sources(); else return QStringList();} DataMap data() const {return m_data;}
Q_PROPERTY(QObject *data READ data NOTIFY dataChanged); Q_INVOKABLE QStringList keysForSource(const QString &source) const;
QObject *data() const {return m_data;} Q_INVOKABLE Plasma::Service *serviceForSource(const QString &source);
Q_PROPERTY(Plasma::Service *service READ service CONSTANT) Q_INVOKABLE void connectSource(const QString &source);
Plasma::Service *service(); Q_INVOKABLE void disconnectSource(const QString &source);
public Q_SLOTS: public Q_SLOTS:
void dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data); void removeSource(const QString &source);
void setupData();
Q_SIGNALS: protected Q_SLOTS:
void newData(const QString &sourceName, const Plasma::DataEngine::Data &data); void dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data);
void intervalChanged(); void setupData();
void engineChanged();
void sourceChanged();
void keysChanged();
void dataChanged();
void sourcesChanged();
private: Q_SIGNALS:
QString m_id; void newData(const QString &sourceName, const Plasma::DataEngine::Data &data);
int m_interval; void sourceAdded(const QString &source);
QString m_source; void intervalChanged();
QString m_engine; void engineChanged();
QStringList m_keys; void sourceChanged();
QDeclarativePropertyMap *m_data; void dataChanged();
Plasma::DataEngine* m_dataEngine; void connectedSourcesChanged();
Plasma::Service *m_service; void sourcesChanged();
QString m_connectedSource;
}; private:
QString m_id;
int m_interval;
QString m_engine;
DataMap m_data;
Plasma::DataEngine* m_dataEngine;
QStringList m_connectedSources;
QStringList m_oldSources;
QStringList m_newSources;
Changes m_changes;
QHash <QString, Plasma::Service *> m_services;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(DataSource::Changes)
} }
#endif #endif