QAbstractItemModelReplica data issue
-
I've created a remote object with a model property. The .rep file is of the form:
class ServiceTest { PROP(QString name="default"); MODEL testModel(name, description, timestamp); }In the client, I can access the name property, and if it is changed by the server, I get a signal and the updated value. The problem is with the model. I can get the QAbstractItemModelReplica, and once I receive the initialized signal, the rowCount reflects the correct number of rows in the model. However, when I iterate over the cells the hasData function returns false and if I call the data function, it returns an invalid QVariant. The rolesNames function returns the correct role names.
-
Here is a minimal example. Instead of using a custom model, I've used a QStringListModel to keep the code simpler.
First the .rep file
class Service { PROP(bool isOn=false); PROP(QString name="default"); MODEL textModel(display); };The server:
#include "rep_Service_source.h" #include <QCoreApplication> #include <QRemoteObjectHost> #include <QStringListModel> #include <QTimer> class Service : public ServiceSimpleSource { Q_OBJECT public: Service() { _textModel.setStringList({"A", "B", "C", "D"}); setName("First value"); setTextModel(&_textModel); connect(&_changeTimer, &QTimer::timeout, this, [this]() { setName(QString("Name #%1").arg(_counter++)); }); _changeTimer.start(4000); } void logModel() { for (int i{}; i < _textModel.rowCount(); ++i) qDebug() << _textModel.data(_textModel.index(i, 0)); } private: QStringListModel _textModel; QTimer _changeTimer; int _counter{1}; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QRemoteObjectHost node(QUrl(QStringLiteral("local:switch"))); Service service; node.enableRemoting(&service, QStringLiteral("MyService")); QObject::connect(&service, &Service::nameChanged, [](QString name) { qDebug() << "Service name changed to" << name; }); return a.exec(); } #include "main.moc"The client:
#include "rep_Service_replica.h" #include <QCoreApplication> #include <QLoggingCategory> #include <QRemoteObjectNode> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QRemoteObjectNode node(QUrl(QStringLiteral("local:switch"))); node.setHeartbeatInterval(1000); std::unique_ptr<ServiceReplica> replica(node.acquire<ServiceReplica>("MyService")); if (!replica->waitForSource() || !replica->isInitialized()) qDebug() << "Replica not valid!"; qDebug() << "replica->isReplicaValid():" << replica->isReplicaValid(); qDebug() << "replica->name:" << replica->name(); auto r = QObject::connect(replica.get(), &ServiceReplica::nameChanged, [](QString name) { qDebug() << QString("replica->name changed to '%1'").arg(name); }); QObject::connect(replica->textModel(), &QAbstractItemModelReplica::initialized, [&replica]() { qDebug() << "textModel.rowCount:" << replica->textModel()->rowCount(); for (int i{}; i < replica->textModel()->rowCount(); ++i) qDebug() << replica->textModel()->data(replica->textModel()->index(i, 0)); }); return a.exec(); }The model replica contains the correct number of rows, but the data is not available!
If I enable logging in the client, It looks like the data is available in the replica:
qt.remoteobjects.models: void fillRow(CacheData*, const QtPrivate::IndexValuePair&, const QAbstractItemModel*, const QList<int>&) row= 0 column= 0 qt.remoteobjects.models: void fillRow(CacheData*, const QtPrivate::IndexValuePair&, const QAbstractItemModel*, const QList<int>&) existed= false qt.remoteobjects.models: void fillCacheEntry(CacheEntry*, const QtPrivate::IndexValuePair&, const QList<int>&) data.size= 1 qt.remoteobjects.models: void fillCacheEntry(CacheEntry*, const QtPrivate::IndexValuePair&, const QList<int>&) role= 0 data= QVariant(QString, "A") qt.remoteobjects.models: void fillRow(CacheData*, const QtPrivate::IndexValuePair&, const QAbstractItemModel*, const QList<int>&) row= 1 column= 0 qt.remoteobjects.models: void fillRow(CacheData*, const QtPrivate::IndexValuePair&, const QAbstractItemModel*, const QList<int>&) existed= false qt.remoteobjects.models: void fillCacheEntry(CacheEntry*, const QtPrivate::IndexValuePair&, const QList<int>&) data.size= 1 qt.remoteobjects.models: void fillCacheEntry(CacheEntry*, const QtPrivate::IndexValuePair&, const QList<int>&) role= 0 data= QVariant(QString, "B") qt.remoteobjects.models: void fillRow(CacheData*, const QtPrivate::IndexValuePair&, const QAbstractItemModel*, const QList<int>&) row= 2 column= 0 qt.remoteobjects.models: void fillRow(CacheData*, const QtPrivate::IndexValuePair&, const QAbstractItemModel*, const QList<int>&) existed= false qt.remoteobjects.models: void fillCacheEntry(CacheEntry*, const QtPrivate::IndexValuePair&, const QList<int>&) data.size= 1 qt.remoteobjects.models: void fillCacheEntry(CacheEntry*, const QtPrivate::IndexValuePair&, const QList<int>&) role= 0 data= QVariant(QString, "C") qt.remoteobjects.models: void fillRow(CacheData*, const QtPrivate::IndexValuePair&, const QAbstractItemModel*, const QList<int>&) row= 3 column= 0 qt.remoteobjects.models: void fillRow(CacheData*, const QtPrivate::IndexValuePair&, const QAbstractItemModel*, const QList<int>&) existed= false qt.remoteobjects.models: void fillCacheEntry(CacheEntry*, const QtPrivate::IndexValuePair&, const QList<int>&) data.size= 1 qt.remoteobjects.models: void fillCacheEntry(CacheEntry*, const QtPrivate::IndexValuePair&, const QList<int>&) role= 0 data= QVariant(QString, "D")However, when I call the data function on the model replica, I get an invalid QVariant!
textModel.rowCount: 4 QVariant(Invalid) QVariant(Invalid) QVariant(Invalid) QVariant(Invalid) -
The only workaround I can find at the moment is to wait for a second or two before trying to read the data from the model. It seems the data is only "fetched" later, but no model signals are emitted once the data is fetched. So, supplying the model to a view doesn't work as the view doesn't get notified to refresh once the data is fetched.