Results 1 to 8 of 8

Thread: model/view design advice appreciated

  1. #1
    Join Date
    Jun 2006
    Posts
    81
    Thanks
    6
    Thanked 5 Times in 4 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows

    Default model/view design advice appreciated

    Hi all,

    I have a custom item model that wraps around QuaZip and is associated with a QTreeView. Think of a ZIP client of sorts. In the view, I am triggering actions on a selection of model indexes that need to act on the according QuaZipFile contents.

    On first impulse, I wanted to iterate the model indexes in the view and request QIODevice data from the model for each index. However, I'd need to Q_DECLARE_METATYPE QIODevice or QuaZipFile, and neither provides a copy c'tor as required. Indeed, Qt strongly discourages copy c'tors on *all* QObjects.

    Of course I could return the file contents as QByteArray data. This, however, would duplicate potentially very large data when all I need might be to stream the data from one device to another - think of exporting files from the archive.

    If any of you could come up with an elegant, well-behaved solution, it would be very much appreciated. Using Qt5 btw. Thanks for your consideration.

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: model/view design advice appreciated

    One thing to keep in mind is that the model is not the data but an interface to the data.
    I.e. the data can usually also be accessed directly.

    I don't know about QuaZip, but for example if you consider a model operating on a normal file system, each file can be addressed by QModelIndex through the model or by filename through the file system API.

    So if the model can map a QModelIndex to a filename, the program can use any of the usual file access facilities to work with the data.

    This approach is used by QFileSystemModel, which has methods to map its indexes to all kinds of file related data types, e.g. filename, fileinfo, filepath, etc.

    Another approach is to have data access methods in the model, e.g. a method that takes a QModelIndex and returns a QFIle*.

    Cheers,
    _

  3. #3
    Join Date
    Jun 2006
    Posts
    81
    Thanks
    6
    Thanked 5 Times in 4 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: model/view design advice appreciated

    I may have managed to obscure my intents by getting too abstract.... :o

    My model wraps the data alright. I overloaded the data() method and introduced custom roles to return e.g. zip paths. This is all fine.

    That which isn't: I wanted to add one additional role, say DeviceRole, to return a QuaZipFile, or even better, a QIODevice (its base class), through the same data() method - for coherence, if you will. To do so, the data returned for this role must cast to QVariant, data()'s return type. As I understood, this requires to Q_DECLARE_METATYPE the custom type in question, which in turn requires the custom type to provide public default c'tor, d'tor, and copy c'tor. However, QIODevice inherits QObject, and QObjects should not provide a copy c'tor (and both QIODevice and QuaZipFile don't), so I'm in a catch-22 here. Please correct me if I'm wrong in any respect.

    I agree this is a very specific home-brewed sort of a problem...

    Quote Originally Posted by anda_skoa View Post
    This approach is used by QFileSystemModel, which has methods to map its indexes to all kinds of file related data types, e.g. filename, fileinfo, filepath, etc.
    Thanks for pointing me to QFileSystemModel. I had a look at its sources: it defines 4 custom roles, of which all but FileIconRole = Qt::DecorationRole relate to types that are represented by QVariant out of the box. What I don't understand is how QIcon casts to a QVariant? But then, QIcon is not a QObject, so the approach sketched out above might have been used (neither in header nor implementation though).

    Quote Originally Posted by anda_skoa View Post
    Another approach is to have data access methods in the model, e.g. a method that takes a QModelIndex and returns a QFIle*.
    This is what I did, but I deem it inelegant at the least with respect to the model/view paradigm.
    Last edited by zaphod.b; 31st May 2013 at 17:51. Reason: disable smilies

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: model/view design advice appreciated

    I guess the question is why you want to return a file through data().

    Does the code that reacts to your selection changes not have access to your model type? I.e. you can't do something like
    Qt Code:
    1. m_model->fileForModelIndex(modelIndex);
    To copy to clipboard, switch view to plain text mode 
    because you don't have access to m_model as a pointer of your model type?

    And you also don't have access to the actual data, as in you can't do
    Qt Code:
    1. QString filename = modelIndex.data(MyRoles::FilenameRole);
    2. ... m_zipFile->file(filename);
    To copy to clipboard, switch view to plain text mode 
    because there is no mappable identifier?

    Cheers,
    _

  5. #5
    Join Date
    Jun 2006
    Posts
    81
    Thanks
    6
    Thanked 5 Times in 4 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: model/view design advice appreciated

    Quote Originally Posted by anda_skoa View Post
    I guess the question is why you want to return a file through data().
    Indeed it is. I may have insufficient grasp of model/view, or some kind of mental block. But as I understand it, calling data() is the preferred means to retrieve any data from the model.

    To have the model return a device through data(index, DeviceRole) would allow me to make as weak assumptions as possible (see below).

    Quote Originally Posted by anda_skoa View Post
    Does the code that reacts to your selection changes not have access to your model type? I.e. you can't do something like
    Qt Code:
    1. m_model->fileForModelIndex(modelIndex);
    To copy to clipboard, switch view to plain text mode 
    because you don't have access to m_model as a pointer of your model type?
    Yes, I currently do not explicitly hold a pointer to the model within the view but access it via view->model() - else I'd lose flexibility, wouldn't I? Explicit knowledge of the model within the view I consider a stronger assumption than to provide data of a certain custom role.

    Quote Originally Posted by anda_skoa View Post
    And you also don't have access to the actual data, as in you can't do
    Qt Code:
    1. QString filename = modelIndex.data(MyRoles::FilenameRole);
    2. ... m_zipFile->file(filename);
    To copy to clipboard, switch view to plain text mode 
    because there is no mappable identifier?
    The zip archive currently is private to the model.
    As you wrote before, the model is an interface to the data. So the data can be accessed bypassing the model. But I'd much rather not for style, flexibility and maintainability reasons.

    I should add that future extensions will likely associate other data with the same view. Other than this data "contains" devices, I do not know at this time.


    PS: I very much appreciate this discussion, as it helps me clarify my thoughts and requirements. It is, however, somewhat academic I have to admit... unless there is a way to return device data, that is

  6. #6
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: model/view design advice appreciated

    Quote Originally Posted by zaphod.b View Post
    But as I understand it, calling data() is the preferred means to retrieve any data from the model.
    Yes, correct, for any data the view or a delegate needs from the model.
    My initial interpretation was that you wanted to have the device for some processing of sorts, in which case direct access to the data is usually the way to go.
    If you need it in a delegate or for some custom view visualizations that data() would be my choice as well.

    Quote Originally Posted by zaphod.b View Post
    To have the model return a device through data(index, DeviceRole) would allow me to make as weak assumptions as possible (see below).
    You can always return a QIODevice*. What kind of view related processing do you plan on doing with the data?

    Quote Originally Posted by zaphod.b View Post
    Yes, I currently do not explicitly hold a pointer to the model within the view but access it via view->model() - else I'd lose flexibility, wouldn't I? Explicit knowledge of the model within the view I consider a stronger assumption than to provide data of a certain custom role.
    Right. As written above, I had initially assumed you wanted to do some processing depending on user actions. If you indeed need the data in the view, then getting it from the model is the best choice.

    Quote Originally Posted by zaphod.b View Post
    The zip archive currently is private to the model.
    As you wrote before, the model is an interface to the data. So the data can be accessed bypassing the model. But I'd much rather not for style, flexibility and maintainability reasons.
    If this is model/view internal then this doesn't make much sense indeed. Sorry for the confusion, "trigger action on selection" sounded to me like doing data processing based on user interaction, something that usually falls outside of the model/view components.

    Quote Originally Posted by zaphod.b View Post
    I should add that future extensions will likely associate other data with the same view. Other than this data "contains" devices, I do not know at this time.
    Hmm, and your data does not have any interface to access those "devices"? or no way of communicating a "handle/identifier"?

    Cheers,
    _

  7. #7
    Join Date
    Jun 2006
    Posts
    81
    Thanks
    6
    Thanked 5 Times in 4 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: model/view design advice appreciated

    Quote Originally Posted by anda_skoa View Post
    Yes, correct, for any data the view or a delegate needs from the model.
    My initial interpretation was that you wanted to have the device for some processing of sorts, in which case direct access to the data is usually the way to go.
    If you need it in a delegate or for some custom view visualizations that data() would be my choice as well.
    Ah light falls into darkness at last!
    So you basically say that data() should only be used for view/delegate related data, whereas other data should (or at least may) be returned by specialized accessors other than data()? This is indeed different from my approach, which is to return all data through data(), no matter if view/delegate related or not.

    Yes, if I follow your approach then there is no (technical) problem at all.

    Quote Originally Posted by anda_skoa View Post
    What kind of view related processing do you plan on doing with the data?
    The problem initially arose when I wanted to drag items from the view and drop its related device data e.g. in a file manager outside my application.

    Quote Originally Posted by anda_skoa View Post
    Right. As written above, I had initially assumed you wanted to do some processing depending on user actions. If you indeed need the data in the view, then getting it from the model is the best choice.
    [...]
    If this is model/view internal then this doesn't make much sense indeed. Sorry for the confusion, "trigger action on selection" sounded to me like doing data processing based on user interaction, something that usually falls outside of the model/view components.
    Sorry but is there a contradiction here? If there is a view, user interaction normally happens with this view, doesn't it?
    Anyway, in your terminology, my drag example is a user interaction on a view's selection, isn't it?

    Quote Originally Posted by anda_skoa View Post
    Hmm, and your data does not have any interface to access those "devices"? or no way of communicating a "handle/identifier"?
    What I by now assume you mean by "data" (in my example the QuaZip object) certainly does have such accessors, and so will any future "device container", by a façade if need be.

  8. #8
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: model/view design advice appreciated

    Quote Originally Posted by zaphod.b View Post
    So you basically say that data() should only be used for view/delegate related data, whereas other data should (or at least may) be returned by specialized accessors other than data()?
    Yes, or even bypassing the model and going directly for the actual content API.
    QAbstractItemModel (and subclasses) provide an abstraction only necessary to be able to re-use the same views and delegates on any kind of content.

    Applications sometimes even have multiple model implementations working on the same context, e.g. only providing access to a subset, etc.
    Maybe consider the model to be an adapter between the actual content API and the view. It shouldn't "hold" the content, merely provide an interface to it that is digestable by Qt's views.

    Quote Originally Posted by zaphod.b View Post
    The problem initially arose when I wanted to drag items from the view and drop its related device data e.g. in a file manager outside my application.

    Sorry but is there a contradiction here? If there is a view, user interaction normally happens with this view, doesn't it?
    Anyway, in your terminology, my drag example is a user interaction on a view's selection, isn't it?
    Ah, I see. I was mostly thinking in terms of handling signals on of the view or item selection model, in which case the processing usually happens outside the view.
    Drag&Drop does indeed require some handling inside the view.

    Hmm. I guess it mainly boils down to whether the Qt item view you have will be the only user interface to the content.

    I usually try to avoid implementing any kind of processing inside a view or slots connected to its signals but instead delegate to some other object that knows nothing about model/view.
    The view or related slot would then only "dereference" the model indexes, basically create non-model/view input for the actual processing class.

    But it of course always depends on the scope of the application, how likely it is to get different UI, etc.

    Cheers,
    _

Similar Threads

  1. Replies: 3
    Last Post: 24th October 2012, 23:47
  2. Model/View separation advice sought
    By ChrisW67 in forum Qt Programming
    Replies: 1
    Last Post: 20th May 2012, 17:32
  3. Replies: 4
    Last Post: 18th April 2012, 19:11
  4. Replies: 1
    Last Post: 1st February 2010, 19:42
  5. Model / View - Design Question
    By antarctic in forum Qt Programming
    Replies: 8
    Last Post: 8th June 2009, 08:39

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.