Wednesday, 29 August 2012

Merged Proxy Model

Kadu IM blog is now part of Qt Planet. This is good time to start sharing some of our solutions with community.

Merged Proxy Model

This is the thing I'm most proud of - a model that can merge any number of other models into one. In Kadu we use it in for:
  • display actions above/below items in QComboBox widgdets
  • display list of Chat and Buddy objects in our roster widget
The second usage forces us to use a complicated structure or models and proxy model, as we have one Chat instance for every Buddy in addition to other instances. So before merging these models we apply filter proxy models that removes one-buddy chats from it. Then we apply more filtering/sorting proxy models on merged model just to be nice for our users.

Features

This proxy model not support everything - for example we haven't tested how it works with multiple columns or submodels with different number of columns. It also does not allows to plug in a model under a subnode of other model - all models are on top level.

It supports following features:
  • updating list of submodels on demand
  • inserting and removing rows (no support for moving)
  • emiting all row and data based signals properly
  • proper mapping to source and from source indexes
  • copying mime daya from submodels
So it is pretty usefull already.

Implementation

I must say that is was very hard piece of work. MergedProxyModel has about 450 lines of code and we have KaduMergedProxyModel on top of it (to implement reverse mapping from values to multiple indexes).

Two basic concepts are used: boundaries list that stores begin and end row index of all submodels in merged model. This value is updated every time a row is inserted or removed. Second one is mapping that maps QModelIndex instances from source to proxy model.

Code

If you want more details or the code please look at our git repository: Kadu on Gitorious. This file is most important: merged-proxy-model.h. Feel free to download and change it. And please send us any update that will make this code better.