This is sort of a best practice question, since I can think of a few ways that would work.
I want to implement an outline view. Let's suppose I want to implement the one in OmniFocus (my aim is very similar):
(I refer to the outline view in the main pane of that screenshot, not to the sidebar.)
So my data type is a task. Any task can have subtasks. Each task has one or zero parent tasks. Classic data model for displaying in an outline view, right?
BUT! I would like to offer the user the ability to group these tasks visually by a property of their choice. They could group them by milestone, or by assigned user, or by component… there'll be a bunch of these. And this grouping should appear in the outline view, at the top level of the hierarchy, just like the "Inbox", "Home" and "Work" items in this OmniFocus screenshot.
So it's fairly obvious that to display the grouping, I should use the built in NSOutlineView methods for drawing a group cell: the outlineView:isGroupItem:
delegate method. The problem is, this setup is assuming that each item in the outline view is represented by an item in whatever data model I've connected it to: so both my tasks and my group headers have to be represented in the data model.
Therefore, just binding to the Core Data table that represents my tasks is a no-no. I could forego bindings all together and just go back to the old style data source methods, but then I lose a bunch of useful stuff. So is there a middle ground?
I could, for example, create another class TaskTemporaryGroup
. I give that class an ivar NSSet that is subtasks
, the same key path as could be used on a task to get its children. Then I can bind my set of TaskTemporaryGroup objects to a tree controller, and it'll arrange the whole tree regardless of the fact that the top level items are a different class to those lower down. I'd have to take care when implementing drag and drop, to make sure that the grouping rows can't be arbitrarily dragged about, but it might work.
The other point of contention is that I would like clicking on the table headers to sort the rows within each group, but not to sort the top level groups. I assume NSTreeController applies the sort descriptors to each level of the hierarchy? I could have my TaskTemporaryGroup class return the same thing (i.e. its desired sorting order, that I've calculated separately) for any of the key paths that I want to be able to sort the rest of the cells on, so that to the framework it would look like they stayed in the same order no matter what property they were sorted by. Is this a good way to go or is it a hack?
So, to summarize:
- How do people suggest I implement this kind of hierarchy, where the top level is a special case and all subsequent levels are the same kind of object?
- Is the way I described, with a class to represent the top level objects that happens to respond to the same key paths as the child objects, a good way to go?
- Does anyone have any tips about how to make sorting work well in this scenario?
- Or will trying to use bindings for this task cause me a world of hurt?
Thanks,
Amy