2
from zope.interface import implements
4
from axiom.slotmachine import _structlike
6
from xmantissa.ixmantissa import ITab, INavigableElement
8
class TabMisconfiguration(Exception):
9
def __init__(self, info, tab):
11
"Inconsistent tab item factory information",
14
class TabInfo(_structlike):
22
"""Represent part or all of the layout of a single navigation tab.
24
@ivar name: This tab's name.
26
@ivar itemFactory: A callable of one argument which returns something which
29
@ivar priority: A float between 0 and 1 indicating the relative ordering of
30
this tab amongst its peers. Higher priorities sort sooner.
32
@ivar children: A tuple of tabs beneath this one.
38
def __init__(self, name, itemFactory, priority, children=()):
40
self.itemFactory = itemFactory
41
self.priority = priority
42
self.children = tuple(children)
45
return '<%s %r/%0.3f %r [%r]>' % (self.__class__.__name__,
52
raise TypeError("%r are not iterable" % (self.__class__.__name__,))
54
def __getitem__(self, key):
55
"""Retrieve a sub-tab from this tab by name.
57
tabs = [t for t in self.children if t.name == key]
58
assert len(tabs) < 2, "children mis-specified for " + repr(self)
63
def loadForAvatar(self, avatar):
64
"""Resolve my 'item' attribute by running my itemFactory against an avatar.
66
if self._item is None:
67
self._item = self.itemFactory(avatar)
70
def pathFromItem(self, item, avatar):
72
@param item: A thing that we linked to, and such.
74
@return: a list of [child, grandchild, great-grandchild, ...] that
75
indicates a path from me to the navigation for that item, or [] if
76
there is no path from here to there.
78
for subnav in self.children:
79
subpath = subnav.pathFromItem(item, avatar)
81
subpath.insert(0, self)
84
myItem = self.loadForAvatar(avatar)
90
def getTabs(navElements):
91
# XXX TODO: multiple levels of nesting, this is hard-coded to 2.
92
# Map primary tab names to a TabInfo
95
# Merge tab information from all nav plugins into one big structure
96
for plg in navElements:
97
for tab in plg.getTabs():
98
if tab.name not in primary:
99
primary[tab.name] = TabInfo(
100
priority=tab.priority,
102
itemFactory=tab.itemFactory,
103
children=list(tab.children))
105
info = primary[tab.name]
107
if info.itemFactory is None:
108
if tab.itemFactory is not None:
109
info.itemFactory = tab.itemFactory
110
elif tab.itemFactory is not None:
111
if info.itemFactory is not tab.itemFactory:
112
raise TabMisconfiguration(info, tab)
114
if tab.priority is not None:
115
info.priority += tab.priority
117
info.children.extend(tab.children)
119
# Sort the tabs and their children by their priority
125
for (name, info) in primary.iteritems():
126
info.priority /= info.number
127
info.children.sort(key=key)
130
Tab(name, info.itemFactory, info.priority, info.children))
132
resultTabs.sort(key=key)
134
return Tab(".", lambda nothing: None, 1.0, resultTabs)