~divmod-dev/divmod.org/1304710-storeless-adapter

« back to all changes in this revision

Viewing changes to Mantissa/xmantissa/webnav.py

  • Committer: glyph
  • Date: 2005-07-28 22:09:16 UTC
  • Revision ID: svn-v4:866e43f7-fbfc-0310-8f2a-ec88d1da2979:trunk:2
move this repository to a more official-looking URL

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
from zope.interface import implements
 
3
 
 
4
from axiom.slotmachine import _structlike
 
5
 
 
6
from xmantissa.ixmantissa import ITab, INavigableElement
 
7
 
 
8
class TabMisconfiguration(Exception):
 
9
    def __init__(self, info, tab):
 
10
        Exception.__init__(
 
11
            "Inconsistent tab item factory information",
 
12
            info, tab)
 
13
 
 
14
class TabInfo(_structlike):
 
15
    __names__ = [
 
16
        'priority',
 
17
        'number',
 
18
        'itemFactory',
 
19
        'children']
 
20
 
 
21
class Tab(object):
 
22
    """Represent part or all of the layout of a single navigation tab.
 
23
 
 
24
    @ivar name: This tab's name.
 
25
 
 
26
    @ivar itemFactory: A callable of one argument which returns something which
 
27
    can be rendered.
 
28
 
 
29
    @ivar priority: A float between 0 and 1 indicating the relative ordering of
 
30
    this tab amongst its peers.  Higher priorities sort sooner.
 
31
 
 
32
    @ivar children: A tuple of tabs beneath this one.
 
33
    """
 
34
 
 
35
    _item = None
 
36
    implements(ITab)
 
37
 
 
38
    def __init__(self, name, itemFactory, priority, children=()):
 
39
        self.name = name
 
40
        self.itemFactory = itemFactory
 
41
        self.priority = priority
 
42
        self.children = tuple(children)
 
43
 
 
44
    def __repr__(self):
 
45
        return '<%s %r/%0.3f %r [%r]>' % (self.__class__.__name__,
 
46
                                          self.name,
 
47
                                          self.priority,
 
48
                                          self.itemFactory,
 
49
                                          self.children)
 
50
 
 
51
    def __iter__(self):
 
52
        raise TypeError("%r are not iterable" % (self.__class__.__name__,))
 
53
 
 
54
    def __getitem__(self, key):
 
55
        """Retrieve a sub-tab from this tab by name.
 
56
        """
 
57
        tabs = [t for t in self.children if t.name == key]
 
58
        assert len(tabs) < 2, "children mis-specified for " + repr(self)
 
59
        if tabs:
 
60
            return tabs[0]
 
61
        raise KeyError(key)
 
62
 
 
63
    def loadForAvatar(self, avatar):
 
64
        """Resolve my 'item' attribute by running my itemFactory against an avatar.
 
65
        """
 
66
        if self._item is None:
 
67
            self._item = self.itemFactory(avatar)
 
68
        return self._item
 
69
 
 
70
    def pathFromItem(self, item, avatar):
 
71
        """
 
72
        @param item: A thing that we linked to, and such.
 
73
 
 
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.
 
77
        """
 
78
        for subnav in self.children:
 
79
            subpath = subnav.pathFromItem(item, avatar)
 
80
            if subpath:
 
81
                subpath.insert(0, self)
 
82
                return subpath
 
83
        else:
 
84
            myItem = self.loadForAvatar(avatar)
 
85
            if myItem is item:
 
86
                return [self]
 
87
        return []
 
88
 
 
89
 
 
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
 
93
    primary = {}
 
94
 
 
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,
 
101
                    number=1,
 
102
                    itemFactory=tab.itemFactory,
 
103
                    children=list(tab.children))
 
104
            else:
 
105
                info = primary[tab.name]
 
106
 
 
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)
 
113
 
 
114
                if tab.priority is not None:
 
115
                    info.priority += tab.priority
 
116
                    info.number += 1
 
117
                info.children.extend(tab.children)
 
118
 
 
119
    # Sort the tabs and their children by their priority
 
120
    def key(o):
 
121
        return -o.priority
 
122
 
 
123
    resultTabs = []
 
124
 
 
125
    for (name, info) in primary.iteritems():
 
126
        info.priority /= info.number
 
127
        info.children.sort(key=key)
 
128
 
 
129
        resultTabs.append(
 
130
            Tab(name, info.itemFactory, info.priority, info.children))
 
131
 
 
132
    resultTabs.sort(key=key)
 
133
 
 
134
    return Tab(".", lambda nothing: None, 1.0, resultTabs)