[Kde-pim] Something for the weekend?

Stephen Kelly steveire at gmail.com
Fri Jan 8 21:24:01 GMT 2010


This is a long email, but not very important to read. It's more of an 
archive of ideas.

After discussion,

Conceptually, the information about how messages should be threaded or 
parented must come from either parents having a listing of their children, 
or children having a reference to their parent. Additional complications 
detailed below mean that each item must be aware of either the entire tree, 
or hold references to all its ancestors. We're going to go with the knowing 
all ancestors option.

The long version:

Evaluating in the parent > child direction would be beneficial from the 
point of view of the proxy model because it would mean that mappings to the 
source model could be created lazily. That's always preferable, and is the 
behaviour of QSFPM and KSelectionProxyModel (on my local machine at least so 
far :)) because it reduces the amount of QPersistentModelIndexes which must 
be created. Doing it that way would mean the isDescendantOf method would 
need to be replaced with a 

/**
  Reimplement this to return the index in the source model vertically 
  below @p index. @index is also in the source model.

  For example, if the source is a list, and the desired structure is

  @code 
  - 1
  - - 2
  - - - 3
  - - 4
  - - 5
  - 6
  @endcode

  Then nextSibling would look something like:

  @code
  {
    if (index == 1) return 6;
    // Return invalid if no next sibling.
    if (index == 6) return QModelIndex();
    // The proxy figures out that some items are missing, 
    // so knows that hasChildren(1) == true; Further mappings aren't created 
    // until requested, for example, when the user click expands the tree.
    if (index == 2) return 4;
    if (index == 4) return 5;
    if (index == 5) return QModelIndex();
    if (index == 3) return QModelIndex();
  }
  @endcode
*/
virtual QModelIndex nextSibling(const QModelIndex &index) = 0; 

However, the problem with evaluating in the parent > child direction is that 
if a child is missing, a grandchild should be a child of the grandparent.

For example,

(Akonadi::Id 7) Alice emails Bob,
-> (Akonadi::Id 56) Bob replies,
-> -> (Akonadi::Id 87) Alice replies to Bob.

If there is one true item hierarchy (and there should be), an Akonadi 
attribute would hold a list of children of size 1: (56,) for 7 (87,) for 56.

If there is a search folder for Alices emails, the list of items would look 
like:

ItemId: 7, Children: (56,)
ItemId: 87: Children ()

There is no way of knowing that 87 is supposed to be a child of 7 in the 
threaded view, because that information is in the not-present item 56. There 
is no way to know that 87 should in fact be a child of 7 without 7 holding 
information about its entire sub tree. That would mean a lot of duplication 
in each item and would obviously be a bad idea.

Storing parent items is then the better idea. There is still a requirement 
to store the entire ancestor hierarchy in the Item attribute in case 
something is filtered out. The above spiel is just there for completeness 
and because it is a better way to implement this from a proxy model point of 
view, even if it's not right for Akonadi. 

In our Akonadi case it makes more sense to use a isDescendantOf method. This 
has the disadvantage that it means all items in the source model must be 
accessed and mapped at proxy model creation time, which means that all items 
in all proxy models in the chain and the root source model must be accessed 
and have mappings created for them, but as the selection proxy model is the 
limiter for what items in the etm need to be accessed, it shouldn't be too 
much.

In this case, the three emails would have attributes like:

ItemId 7: Parent chain: ()
ItemId 56: Parent chain: (7,)
ItemId 87: Parent chain: (56, 7)

This means that even if 56 is filtered out, 87 still has information that it 
should be a descendant of 7. The isDescendantOf method should then be 
trivial to write too.

The case of items having multiple parents is also handled in this scenario. 
If the message threading agent determines that an item has multiple possible 
parents, they would simply all be put in the list, in an arbitrary or 
specific order.

For example, if 56 could have parents 34, 67, 45, and grandparents could be 
78, 46, 98, 23, 25, 12 (if each of the possible parents itself has two 
possible parents). 

Then the attribute would contain (34, 67, 45, 78, 46, 98, 23, 25, 12). 

Apparently an email having multiple possible parents should be relatively 
rare, so we can optimize for the common case. There doesn't seem to be any 
other solution anyway.

Similarly, tasks with common subtasks should be possible to handle too. In 
the case of sub tasks in the last email, we could have something like this 
in two different views in different applications or plasmoids:

- 1
- - 2
- - 3

- 4
- - 2
- - 5

Here, 2 would have an attribute identifying two possible parents, 4, and 1, 
so they would appear in the right place even if one model showed the same 
subtask twice (in different tasks) as long as no task was a descendant task 
of itself.

As suggested earlier at Osnabruck, if we get a lot of use cases of items 
with multiple parents, we can just rename it The Great Exploding Ancestor 
Tree Model and be done with it.

All the best,

Steve.



_______________________________________________
KDE PIM mailing list kde-pim at kde.org
https://mail.kde.org/mailman/listinfo/kde-pim
KDE PIM home page at http://pim.kde.org/



More information about the kde-pim mailing list