Den tors 4 juni 2020 kl 09:00 skrev Elvis Stansvik <[email protected]>: > > Den ons 3 juni 2020 10:38Jonathan Purol <[email protected]> skrev: >> >> Hello everyone, >> >> I've been in a bit of a tough spot recently with `QAbstractItemModel`. >> I'll try to delineate my situation, then my problem, and then the >> potential solutions and why I think they're all inferior to what I wish >> to have. >> >> We have a desktop applications using QtWidgets, however instead of a >> data model we obtain our data from an "external source" (this is a >> little complicated in our use case, but you can think of it as a remote >> server for all intents and purposes). >> Now the server emits events for changes in the underlying data model. >> For example there is an event for `itemAdded` with all appropriate data >> points being passed to us via a web socket. >> This is all fine and dandy. >> >> The problem arises when I try to now connect this to the model >> representing all `Item` objects. >> Qt requires both `beginInsertRows` and `endInsertRows` to be called when >> these changes are made. Furthermore it requires the underlying data to >> really only be changed in-between those calls. I.e. `rowCount` should >> return something different at the time `beginInsertRows` is called than >> at the time `endInsertRows` is called. So far so good. But we don't >> really have that in-between point. We only get notified when the change >> has already happened. >> >> There are a few solutions I could see here: >> 1. Keep a local cache of all of the data, update it incrementally when >> changes come through with this pattern: >> - change events arrives >> - emit "begin change" >> - update internal data >> - emit "end change" >> >> 2. Keep a local cache of all the data on a per-model basis then repeat >> as can be seen above >> >> I dislike both of these changes, even if they do solve the issue >> flawlessly. The reason for that is that it is quite a bit of overhead. >> Both regarding code complexity as well as regarding memory usage and >> performance. Don't get me wrong, having a cache is important, and we >> will have one as well. What doesn't stick right with me is a cache that >> in turn keeps track of all the data all the time. >> >> Now you might say "why not just have the server emit both a "before" and >> a "after" change event for whatever happens. >> Yeah, I would love to do that - but with Qt's current setup it just >> isn't possible. >> What Qt is missing is an `abortInsertRows` function to reset the model's >> internal state. >> There are many, many things that can go wrong in our setup, even IF the >> data was successfully updated. And if we cannot tell Qt to revert the >> changes in case such an error occurs we cannot possible use this approach. >> The only solution I would see here would be to call >> `begin/endResetModel` in case an error occurs, but that sounds like >> trying to put a nail into a coffin with a wrecking ball. > > > I understand your problem. I've not been in your situation, but how about > > - Change server to emit before and after events, plus a cancel event. > > - Upon receiving a before event, call beginInsertRows, > > - Upon receiving an after event, call endInsertRows, > > - Upon receiving a cancel event, call endInsertRows, then call > beginRemoveRows, remove the cancelled rows, then call endRemoveRows. > > Could that work? I don't think the models would ever show the cancelled data, > as control never returned to the event loop during the dance in the last step.
Thinking a bit more (and I'm no expert), if I understand your setup correctly, I still think there's a race that could confuse your views. If I understand you right, your model always reports "live" data from the server, which I presume means your data(..) returns data fetched from the server. If so, then I think this scenario could happen (?): 1. View requests some data at index X, and gets back data Y. 2. Something happens on the server so the data changes. 3. The server sends out a change event. 4. View again requests some data at index X, but gets back data Z (!). 5. The change event arrives at your application. ... This is a situation in which the data returned at some index changes from the POV of the view, with no beginInsertRows/endInsertRows in between, which I think is a breach of the Qt model/view contract. I may be wrong though, so maybe someone more knowledgeable can step in an confirm/deny. Cheers, Elvis > > Cheers, > Elvis > >> >> My questions now are as follows: >> Is there any chance `abort*` methods would be added in the future? >> Could I perhaps add such a method myself? >> Is it safe to just call `endInsertRows` when no changes were made? >> Is there a simple solution I overlooked? >> >> Sincerely, >> Jonathan Purol >> >> _______________________________________________ >> Interest mailing list >> [email protected] >> https://lists.qt-project.org/listinfo/interest _______________________________________________ Interest mailing list [email protected] https://lists.qt-project.org/listinfo/interest
