[Interest] Models and aborting structural changes

Jonathan Purol contact at folling.de
Wed Jun 3 10:36:49 CEST 2020

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.

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?

Jonathan Purol

More information about the Interest mailing list