1# -*- coding: iso-8859-1 -*-
2"""
3    MoinMoin - LocalSiteMap action
4
5    The LocalSiteMap action gives you a page that shows
6    nearby links.  This is an example of what appears on the
7    page (names are linkable on the real page):
8
9    MoinMoin
10         GarthKidd
11              OrphanedPages
12              WantedPages
13         JoeDoe
14              CategoryHomepage
15                   CategoryCategory
16                   WikiHomePage
17              JoeWishes
18              WikiWiki
19                   OriginalWiki
20
21    @copyright: 2001 Steve Howell <showell@zipcon.com>,
22                2001-2004 Juergen Hermann <jh@web.de>
23    @license: GNU GPL, see COPYING for details.
24"""
25
26from MoinMoin import wikiutil
27from MoinMoin.Page import Page
28
29class MaxNodesReachedException(Exception):
30    pass
31
32def execute(pagename, request):
33    _ = request.getText
34
35    # This action generate data using the user language
36    request.setContentLanguage(request.lang)
37
38    request.theme.send_title(_('Local Site Map for "%s"') % (pagename), pagename=pagename)
39
40    # Start content - IMPORTANT - witout content div, there is no
41    # direction support!
42    request.write(request.formatter.startContent("content"))
43
44    request.write(LocalSiteMap(pagename).output(request))
45
46    request.write(request.formatter.endContent()) # end content div
47    request.theme.send_footer(pagename)
48    request.theme.send_closing_html()
49
50class LocalSiteMap:
51    def __init__(self, name):
52        self.name = name
53        self.result = []
54
55    def output(self, request):
56        tree = PageTreeBuilder(request).build_tree(self.name)
57        #self.append("<small>")
58        tree.depth_first_visit(request, self)
59        #self.append("</small>")
60        return """
61<p>
62%s
63</p>
64""" % ''.join(self.result)
65
66    def visit(self, request, name, depth):
67        """ Visit a page, i.e. create a link.
68        """
69        if not name:
70            return
71        _ = request.getText
72        pg = Page(request, name)
73        action = __name__.split('.')[-1]
74        self.append('&nbsp;' * (5*depth+1))
75        self.append(pg.link_to(request, querystr={'action': action}))
76        self.append("&nbsp;<small>[")
77        self.append(pg.link_to(request, _('view')))
78        self.append("</small>]<br>")
79
80    def append(self, text):
81        self.result.append(text)
82
83
84class PageTreeBuilder:
85    def __init__(self, request):
86        self.request = request
87        self.children = {}
88        self.numnodes = 0
89        self.maxnodes = 35
90
91    def mark_child(self, name):
92        self.children[name] = 1
93
94    def child_marked(self, name):
95        return name in self.children
96
97    def is_ok(self, child):
98        if not self.child_marked(child):
99            if not self.request.user.may.read(child):
100                return 0
101            if Page(self.request, child).exists():
102                self.mark_child(child)
103                return 1
104        return 0
105
106    def new_kids(self, name):
107        # does not recurse
108        kids = []
109        for child in Page(self.request, name).getPageLinks(self.request):
110            if self.is_ok(child):
111                kids.append(child)
112        return kids
113
114    def new_node(self):
115        self.numnodes = self.numnodes + 1
116        if self.numnodes == self.maxnodes:
117            raise MaxNodesReachedException
118
119    def build_tree(self, name):
120        self.mark_child(name)
121        tree = Tree(name)
122        try:
123            self.recurse_build([tree], 1)
124        except MaxNodesReachedException:
125            pass
126        return tree
127
128    def recurse_build(self, trees, depth):
129        all_kids = []
130        for tree in trees:
131            kids = self.new_kids(tree.node)
132            for kid in kids:
133                newTree = Tree(kid)
134                tree.append(newTree)
135                self.new_node()
136                all_kids.append(newTree)
137        if len(all_kids):
138            self.recurse_build(all_kids, depth+1)
139
140class Tree:
141    def __init__(self, node):
142        self.node = node
143        self.children = []
144
145    def append(self, node):
146        self.children.append(node)
147
148    def depth_first_visit(self, request, visitor, depth=0):
149        visitor.visit(request, self.node, depth)
150        for c in self.children:
151            c.depth_first_visit(request, visitor, depth+1)
152
153