PDA

View Full Version : QAbstractItemModel::reset() obsolete?



tuli
14th January 2019, 13:40
Hi,


I have a model whose backingstore can change or outright die without me knowing what exactly changed, just that something changed. So I need to reset the entire model. I figured the method reset() is the perfect match here:

https://doc.qt.io/qt-5/qabstractitemmodel-obsolete.html#reset

But it's obsolete, and Qt doc suggest I replace it with a beginResetModel() + endResetModel().


Problem is obviously that I dont know when my model is about to be reset, so I cant call beginResetModel before.



What's the protocol here? Should I just ignore the fact that the data is already reset and do


beginResetModel()
endResetModel()

Documentation explicitly says:


You must call this function before resetting any internal data structures in your model or proxy model.


or should I just emit a lone "endResetModel()" call? That feels wrong.

d_stranz
14th January 2019, 17:03
The call to beginResetModel() ensures that any view or proxy that is connected to your model will not attempt to do any updates until the endResetModel() method is called. While the model is being reset, pointers, model indexes, and other things used by views or proxies could become invalid and thus cause a crash.


Problem is obviously that I dont know when my model is about to be reset, so I cant call beginResetModel before.

That seems really unlikely. It's your code after all. Somewhere you have a method that must rebuild the internal data structure used by your model, and that's the place where you would call the begin / endResetModel() methods. Somewhere else, you must have a method that gets called to trigger that rebuild. It can't just decide on its own...

If you don't have such a place (eg. you are simply replacing a pointer to an internal data structure inside your model wrapper on a reset), then you have to ensure that you call beginResetModel() before messing around with the object the pointer references or create a new, duplicate instance of the data structure so that the old one continues to remain valid until it is replaced.

tuli
14th January 2019, 23:16
My model is read-only, does that change anything?


The model is grabbing data from the network / from a networkshare. That share might go down without notice, and i have to handle it gracefully. Surely there must be some way to handle that? As far as I can tell the reset() method that is now labeled "obsolete" did exactly that...

SqlModels should have the exact same problem with remote databases, so I find it difficult to imagine this problem hasnt come up so far.

d_stranz
15th January 2019, 01:04
My model is read-only, does that change anything?

I presume you mean read-only with respect to views or proxies, right? No, it doesn't make any difference - if a view or proxy can call data() on your model and get non-valid results, then it's a problem.


The model is grabbing data from the network / from a networkshare. That share might go down without notice, and i have to handle it gracefully. Surely there must be some way to handle that? ... SqlModels should have the exact same problem with remote databases

Is your app checking to see that the network connection is still alive? (Just like I presume SQL drivers also have some sort of "heartbeat" monitor to see that their connection to a remote database is still alive). Do you observe network connection timeouts when you get no response to a request for more data? In any case, you should make your app robust enough that it can detect that the remote share has gone down and "fail" gracefully. Failure then becomes a matter of either freezing in place the last set of valid data or deleting the data if having stale data is inappropriate, and having your app tell the user that the connection was lost.

And even when the connection is still alive and well, either you are polling the share to see if anything has changed or you are waiting for the share to send you a "data changed" signal of some sort - it is at the point where you handle that change that you need to call the begin / endResetModel() pair.

The only way you might be able to get away with not doing it is if your app (and everything it depends on) is single-threaded and you can guarantee that there will be no event processing from the time you begin your update until the end - that is, no signals emitted or slots invoked where your model data is involved. Then you can probably call begin / end immediately in sequence and things will be fine. But network communications are inherently asychronous and almost certainly multithreaded, so I would be cautious in assuming you could get away with it.

tuli
15th January 2019, 07:55
Sadly it's a multithreaded up, but yes I check and know when the share goes down. At that point I used to call reset(). But I dont know how I could replace that reset() call at this point with the new beg..end..() syntax, since the data is gone at that point.


Failure then becomes a matter of either freezing in place the last set of valid data or deleting the data if having stale data is inappropriate, and having your app tell the user that the connection was lost.

I want to delete the data, but I dont understand how I can do that? (There is no cache of my own between the model and the network share or something like that.)

d_stranz
15th January 2019, 17:13
There is no cache of my own between the model and the network share or something like that.

Then I guess I don't understand how you have implemented your model. In most cases of a custom model, the model is implemented as a wrapper around some other custom data structure. The app updates the custom data structure and tells the model to notify its listeners (views or proxies) that the data is changing / has changed, through the various begin... / end... method pairs. Even the specialized models (QSqlQuery, QFileSystemModel, etc.) are wrappers around data structures that map external data into the Model / View architecture and take care of these notifications internally.

anda_skoa
16th January 2019, 21:10
If you have no local data then simply do the begin/end calls.

Cheers,
_