disorderedmaterials / dissolve

Structure refinement software for total scattering data
GNU General Public License v3.0
9 stars 16 forks source link

Data Model Interface for Qt #1902

Open trisyoungs opened 2 months ago

trisyoungs commented 2 months ago

Describe the feature / issue There are many reasons to use models for managing the viewing and editing of our data in the Dissolve GUI, however there is something of a disconnect in the way we manage data between the CLI "core" code and the Qt GUI.

Can we implement a custom "model" which sits alongside, e.g., a std::vector<CustomData> and provides "row" addition and deletion, read/write access to data, much as a QtAbstractItemModel does, but without any of the Qt? A companion Qt class in the GUI could then be designed to directly use this non-Qt model to achieve the desired result in the GUI. Why bother doing this? I'm thinking this would allow:

trisyoungs commented 2 months ago

@rprospero Thoughts?

rprospero commented 2 months ago

I've had a similar idea and I guess it's time to try and formalise a bit of the design. Or it's just time for me to vastly overengineer something.

We're likely thinking of the same design (i.e. a template class that takes a reference to a vector and can be passed callbacks for insertion, update, and delete). Here are the issues that I'm currently worried about.

  1. It's easy to wrap the insertion and removal commands, but modifying values is much trickier, especially since the callback needs to be called before and after modification. I see two ways of handling this a. For modifications, the model returns a tiny wrapper around the vector reference. It has all of the standard vector methods, so it can act as a drop in for our current methods. Additionally, the constructor calls the beginReset callback and the destructor calls the endReset callback to ensure that the GUI model gets updated after the modifications are finished b. We provide a method that calls a lambda on each element in the vector. The lambda returns an optional new value. If the value isn't empty, update the value and call the modification callback for that index. This is more awkward to use (e.g. must use lambda callbacks, can only look at one value at a time), but does have the advantage of only updating the parts of the model that actually changed.
  2. We can make a template class that implements QAbstractItemModel and connects into the model. However, our model wrapper can't provide any of the display. My thought there is to make two overloaded functions: QVariant asTableRow(&T value, int column, int role) and bool writeTableRow(QVariant value, &T old, int column, int role). There would be two additional template functions int tableColumns<T>() and QVariant tableColumnHeaders<T>(int column, int role). If we implement these overloads and specialise the template functions for the types, then it should be possible to drop in our template model class with no extra boiler plate.