[Solved] QAbstractProxyModel::setData does not emit dataChanged - is it a bug or not?
-
Hi there,
I'm developing a Qt 4.8.0 application and using the Interview Framework. I have one model for my data and several proxy models (they inherit QAbstractProxyModel directly) that filter and modify the underlying data. My view classes use only these proxy models.
I've just noticed that when I change some data through a proxy model, no dataChanged signal is emitted by my proxy models, opposing what I assumed. My assumption is based on Qt Docs: http://qt-project.org/doc/qt-4.8/qabstractitemmodel.html#setData:
bq. The dataChanged() signal should be emitted if the data was successfully set.
and http://qt-project.org/doc/qt-4.8/qabstractitemmodel.html#dataChanged
bq. When reimplementing the setData() function, this signal must be emitted explicitly.
When I looked into the Qt sources I found that QAbstractProxyModel reimplements setData: it maps the given index with mapToSource and call its sourceModel's setData with this index and the given value and role. But it does not emit dataChanged signal there.
My question: is this a bug or a "feature" of Qt? Should I report it in the bug tracker?
I really think that the dataChanged is better to be emitted in proxy models, because there is no other way to notify views about changes. However I accept if developers made a decision there, but then I suggest to document it at QAbstractProxyModel::setData like this:
bq. If you subclass QAbstractProxyModel, you should reimplement this function to emit dataChanged signal here if you want your views to be notified about changes.
Thank you for your suggestions and replies!
Best regards,
winnetou
[edit: fixed typo in title, Eddy]
-
I had a similar problem recently:
http://qt-project.org/forums/viewthread/14601/
Does this help?When changing data via the proxy, it gets passed down to the source model which in turn emits dataChanged which gets passed back to the connected proxy model which forwards the dataChanged signal if the proxy model doesn't hide/filter the affected rows/columns.
-
Indeed, DerManu is right. It is not up to the proxy to, on it's own, decide that it should signal changes. Changes are made (or rejected!) on the source model, and it is the source model's responsibility to signal any such changes. Then, if the proxy receives such signals, it should check if the index(es) in question are available from the proxy, and if so, re-emit the signal it got from the underlying source model with the translated indices.
Your suggestion would break the design. How would the proxy know if the source model actually changed the data, and what data was affected by such a change?
-
Thank you both for your replies, I've got it know. I followed DerManu's suggestions and my program now works fine.
However I'd like to enlight my suggestion a bit better. My idea was that the proxy's setData function could use the return value of its source model's setData to decide whether the changes were successful and if so, it could safely emit the dataChanged signal for itself (naturally, the proxy only calls its source's setData if the given index is available in the proxy).
I think I am right at this point at least in that it can work - but I now see the idea of the current design and that my solution breaks it.For now I have two more questions:
First i don't think this design idea is clearly documented (at least I cannot find it). Where can I suggest an extension for the docs or extend it myself with that? I see that some users can add notes to doc pages, but I currently can't.
Secondly what is the way of closing this thread and mark it as [solved]?
-
[quote author="winnetou" date="1336659665"]My idea was that the proxy's setData function could use the return value of its source model's setData to decide whether the changes were successful and if so, it could safely emit the dataChanged signal for itself[/quote]But then the dataChanged signal would be emitted twice, once from proxyModel itself and once forwarded through the proxy model from the source model. If you remove the forwarding your view connected to the proxy model won't get updates if setData is called directly on the source model somewhere outside the proxy model. All in all I don't quite see how this should improve anything, it actually makes things a bit worse. From a design point of view it's not that good either because you give the proxy model deeper functionality which should actually be the responsibility of the source model. The proxy model should be a "transparent" layer between source and view that only does redirecting/blocking, and not do its own thing in terms of talking to the view without the source being the cause.
[quote author="winnetou" date="1336659665"]First i don't think this design idea is clearly documented (at least I cannot find it).[/quote]While it may not say explicitly that QAbstractProxyModel forwards dataChanged signal upwards and setData calls downwards, that's kind of implicitly clear, when reading the setData/dataChanged docs and the "introduction to Model/View-Proxy models":http://qt-project.org/doc/qt-4.8/model-view-programming.html#proxy-models. Otherwise it wouldn't make sense using a proxy model pipelined between source and view. Information would be lost.
[quote author="winnetou" date="1336659665"]Where can I suggest an extension for the docs or extend it myself with that? I see that some users can add notes to doc pages, but I currently can't.[/quote] If you want to edit the Qt-docs you could either file a bug report and suggest it there, or, even better, commit a change to the appropriate file itself (You'd need to browse through the gitorious source tree to find the .cpp/.h file that contains the docs you want to change).
Adding a note to the docs here on qt-project.org should be possible for you, too. At least I see an "add note" link at the bottom of the docs page.
[quote author="winnetou" date="1336659665"]Secondly what is the way of closing this thread and mark it as [solved]?[/quote]I think by editing the first post and prepeding "[solved]" to the thread title.
-
[quote author="DerManu" date="1336662176"]If you remove the forwarding your view connected to the proxy model won't get updates if setData is called directly on the source model somewhere outside the proxy model.[/quote]
It's your point.
[quote author="DerManu" date="1336662176"]While it may not say explicitly that QAbstractProxyModel forwards dataChanged signal upwards...[/quote]
Does it? I'll give this another try with a simple project later, but I had to write this forwarding by hand in my project. I experienced that QAbstractItemModel does not do it automatically. Or did I misunderstand something you wrote?
[quote author="DerManu" date="1336662176"]Adding a note to the docs here on qt-project.org should be possible for you, too. At least I see an "add note" link at the bottom of the docs page.
...
I think by editing the first post and prepeding "[solved]" to the thread title.[/quote]Thanks for the tips.
-
[quote author="winnetou" date="1336663636"]
[quote author="DerManu" date="1336662176"]If you remove the forwarding your view connected to the proxy model won't get updates if setData is called directly on the source model somewhere outside the proxy model.[/quote]It's your point.
[quote author="DerManu" date="1336662176"]While it may not say explicitly that QAbstractProxyModel forwards dataChanged signal upwards...[/quote]
Does it? I'll give this another try with a simple project later, but I had to write this forwarding by hand in my project. I experienced that QAbstractItemModel does not do it automatically. Or did I misunderstand something you wrote?
[/quote]
QAbstractItemModel does not, but the proxy models should (and in my experience, do) forward the signal. -
Sorry, it was just a mistype, I meant QAbstractProxyModel. I will check it once more. Thanks.
-
I investigated this signal transfer thing a little bit more. I created a subclass of QTreeView and reimplemented its dataChanged to print some debug output (in addition to set the data).
Then I experienced the following (connecting different proxies between a simple QStandardItemModel and this view):
QAbstractProxyModel does not forward dataChanged signal: I created a minimal subclass of QAbstractProxyModel, specifically a naive implementation of QIdentityProxyModel. I implemented only the pure virtual methods and the proxy transferred all data without loss (and dataSet requests too!), but the debug output was never come.
QIdentityProxyModel and other predefined proxy models really transfer this signal, I got the debug output if I used any of them.
I know that the suggested practice is to subclass QIdentityProxyModel instead of QAbstractProxyModel. Also for those who must use an older version than Qt 4.8.0 (like me) it is clearer to subclass QAbstractProxyModel instead of QSortFilterProxyModel for some specific reason.
So I think I will (if I can) add a note on this in the docs because it's (in my opinion) a good-to-know thing.
Thank you again for this discussion. I'll mark this thread [solved], but I kindly welcome your further notes, remarks or ideas.