[Qt-interest] ModelView - how to use proxies to filter this data?

Stephen Kelly steveire at gmail.com
Mon Nov 30 13:55:02 CET 2009


Daniel Price wrote:

> I need to use modelView in an advanced way.
> 
> I have data like this (contrived example):
> 
> People{}
> ---person1{first name, last name,address1,address2,phone, email}
> ---person2{first name, last name,address1,address2,phone, email}
> ---person3{first name, last name,address1,address2,phone, email}
> Companies{}
> ---company1{name, address1, address2,phone,website}
> ------product1{name,type,price}
> ------product2{name,type,price}
> ---company2{name, address1, address2,phone,website}
> ------product1{name,type,price}
> ------product2{name,type,price}
> 
> The data is hierarchical but sub-categories of data have different columns
> and different data for each column. In the above example, 'person' records
> have 6 columns, but 'product' records have 3. The actual data I'm dealing
> with is a lot more complex.
> 
> Now an QAbstractItemModel-derived class can be used as an adaptor for this
> but the data cannot (practically) by displayed within a QTreeView. So my
> idea is to use QAbstractItemProxy-derived classes to wrap the model. The
> primary single-column TreeView will display the following as headers:
> 
> People
> ---person1
> ---person2
> ---person3
> Companies
> ---Company1
> ---Company2
> 
> When a Person or Company row is selected, a secondary TableView with
> display the data, stored as child indexes of that item in the original
> model.

Have a closer look at the models/proxies used in Akonadi. The 
EntityTreeModel is the invisible "core" model, the 
EntityMimeTypeFilterProxyModel creates something like your overview proxy 
model above, and the KSelectionProxyModel uses the selection from that to 
give a listing related to what you have selected. The result of that is 
usually then further processed by another EntityMimeTypeFilterProxyModel, 
but depending on your real data, you might not need to do something similar.

http://api.kde.org/4.x-api/kdepimlibs-
apidocs/akonadi/html/classAkonadi_1_1EntityTreeModel.html

http://api.kde.org/4.x-api/kdepimlibs-
apidocs/akonadi/html/classAkonadi_1_1EntityMimeTypeFilterModel.html

http://api.kde.org/4.x-api/kdelibs-
apidocs/kdeui/html/classKSelectionProxyModel.html

There is a bit of hackery between those classes to make different headers 
appear in the different views (see the use of EntityTreeModel::HeaderGroup). 
If you come up with a better way to do that than I did, let me know.

You can see how they are used together in akonadiconsole:

http://websvn.kde.org/trunk/KDE/kdepim/akonadi/akonadiconsole/browserwidget.cpp?view=markup

(AkonadiBrowserModel is-a EntityTreeModel)

and KAddressBook (including ASCII art :) )
http://websvn.kde.org/trunk/KDE/kdepim/kaddressbook/mainwidget.cpp?view=markup

It's not exactly the same as what you want to do, but it's good for ideas of 
how to do this kind of stuff.

> 
> So I would need four models - the original (invisible) model with all the
> data, an Overview proxy model for the primary tree, a Person proxy model,
> and  Company proxy model.

That could work. You might not have to do the headerData hackery if Person 
and Company are different QSFPM subclasses. The akonadi equivalent is the 
EntityMimeTypeFilterModel which handles both.

> 
> I'm having trouble implementing this due to the lack of
> examples/information available. Here is what I have discovered:
> 
> 1)      It looks like QAbstractProxyModel-derived classes must propagate
> all signals emitted by the source model or it will do nothing (the
> examples I've seen work only on static data created before the model is
> hooked up so it does not matter).

Yes.

> 
> 2)      From studying the QSortFilterProxyModel implementation, it seems
> that proxies cannot share indexes from the source model - they must create
> their own.

Yes.

> 
> I just need to be able to pick out the data from the primary model for
> each view. Does anyone have examples on how to proceed? No-one seems to
> have done this publically outside of Nokia so information is rare!

I couldn't find anything either at the start, and it has taken a long time 
to get this far.

> 
> I can think of discrete ways of doing the same thing without proxies but
> having everything in a primary model has certain advantages (simplified
> undo for example).

And not-broken selection, caching possibilities etc.

For more advanced model-view stuff see my blog, particularly:

http://steveire.wordpress.com/2009/10/01/akonadi-its-all-sausage/
http://steveire.wordpress.com/2009/10/06/cache-invalidation-in-akonadi-
models/
http://steveire.wordpress.com/2009/06/23/testing-non-trivial-generic-proxy-
models/

Note that KSelectionProxyModel is covered by the LGPL, so you must be aware 
of your licencing obligations if you want to use it. Also, it is currently 
broken in a subtle way and I have a large patch pending to fix it. 

Final tip: Never use the internalPointer or internalId of a QModelIndex in 
the source model when implementing a proxy model.


All the best,

Steve.

> 
> 
> Daniel Price
> Software Engineer
> FXhome Limited
> 
> 
> ________________________________
> This email is confidential. It may also be privileged or otherwise
> protected by work product immunity or other legal rules. If you are not
> the intended recipient please notify the sender. Please delete the message
> from all places in your computer where it is stored. You should not copy
> the email or use it for any purpose or disclose its contents to any other
> person.To do so may be unlawful. Email is an informal means of
> communicating and may be subject to data corruption accidentally or
> deliberately. For this reason it is inappropriate to rely on advice
> contained in an email without obtaining written confirmation of it first.
> 
> FXhome Limited is a limited company registered in England and Wales.
> Registered number: 04172812. Registered office: The Henderson Business
> Centre, Ivy Road, Norwich, Norfolk, NR5 8BF, U.K.




More information about the Qt-interest-old mailing list