source: products/quintagroup.dropdownmenu/trunk/quintagroup/dropdownmenu/browser/viewlets.py @ 3236

Last change on this file since 3236 was 3236, checked in by kroman0, 13 years ago

Pyflakes fix

  • Property svn:eol-style set to native
File size: 9.9 KB
Line 
1# -*- coding: utf-8 -*-
2from Acquisition import aq_inner
3
4from zope.component import getMultiAdapter
5
6from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
7from Products.CMFCore.utils import getToolByName
8from Products.CMFCore.interfaces import IAction, IActionCategory
9from Products.CMFCore.ActionInformation import ActionInfo
10from Products.CMFPlone.utils import versionTupleFromString
11
12from plone.memoize.instance import memoize
13from plone.memoize.compress import xhtmlslimmer
14from plone.app.layout.viewlets import common
15from plone.app.layout.navigation.navtree import buildFolderTree
16from plone.app.layout.navigation.interfaces import INavtreeStrategy
17
18from quintagroup.dropdownmenu.browser.menu import DropDownMenuQueryBuilder
19from quintagroup.dropdownmenu.util import getDropDownMenuSettings
20
21from time import time
22from plone.memoize import ram
23import copy
24
25
26def menu_cache_key(f, view):
27    try:
28        section = view.context.getPhysicalPath()[2]
29    except:
30        section = ""
31
32    return view.__name__ + \
33           section + \
34           str(time() // (60 * 5))  # Every five minutes
35                                    # Note that the HTTP RAM-cache
36                                    # typically purges entries after
37                                    # 60 minutes.
38
39
40def tabs_cache_key(f, view, site_url):
41    return site_url + str(time() // (60 * 60))
42
43
44class GlobalSectionsViewlet(common.GlobalSectionsViewlet):
45    index = ViewPageTemplateFile('templates/sections.pt')
46    recurse = ViewPageTemplateFile('templates/sections_recurse.pt')
47
48    def update(self):
49        # we may need some previously defined variables
50        #super(GlobalSectionsViewlet, self).update()
51
52        # prepare to gather portal tabs
53        context = aq_inner(self.context)
54        self.conf = self._settings()
55        self.tool = getToolByName(context, 'portal_actions')
56        self.site_url = getToolByName(context, 'portal_url')()
57        self.context_state = getMultiAdapter((self.context, self.request),
58                                              name="plone_context_state")
59        self.context_url = self.context_state.is_default_page() and \
60            '/'.join(self.context.absolute_url().split('/')[:-1]) or \
61            self.context.absolute_url()
62
63        self.cat_sufix = self.conf.nested_category_sufix or ''
64        self.cat_prefix = self.conf.nested_category_prefix or ''
65
66    @property
67    def portal_tabs(self):
68        tabs = []
69
70        # fetch actions-based tabs?
71        if self.conf.show_actions_tabs:
72            tabs.extend(self._actions_tabs())
73
74        # fetch content structure-based tabs?
75        if self.conf.show_content_tabs:
76            # put content-based actions before content structure-based ones?
77            if self.conf.content_before_actions_tabs:
78                tabs = self._content_tabs() + tabs
79            else:
80                tabs.extend(self._content_tabs())
81
82        return tabs
83
84    def _actions_tabs(self):
85        """Return tree of tabs based on portal_actions tool configuration"""
86        conf = self.conf
87        tool = self.tool
88
89        # check if we have required root actions category inside tool
90        if conf.actions_category not in tool.objectIds():
91            return []
92        listtabs = []
93        res, listtabs = self.prepare_tabs(self.site_url)
94        res = copy.deepcopy(res)
95        self.tabs = listtabs
96
97        # if there is no custom menu in portal tabs return
98        if not listtabs:
99            return []
100
101        current_item = -1
102        delta = 1000
103        for info in listtabs:
104            if  self.context_url.startswith(info['url']) and \
105                len(self.context_url) - len(info['url']) < delta:
106                delta = len(self.context_url) - len(info['url'])
107                current_item = listtabs.index(info)
108        self.id_chain = []
109
110        if current_item > -1 and current_item < len(listtabs) and \
111            (listtabs[current_item]['url'] != self.site_url or \
112            listtabs[current_item]['url'] == self.site_url and \
113            self.context_url == self.site_url):
114
115            self.mark_active(listtabs[current_item]['id'],
116                             listtabs[current_item]['url'])
117
118        self._activate(res)
119        return res
120
121    @ram.cache(tabs_cache_key)
122    def prepare_tabs(self, site_url):
123        def normalize_actions(category, object, level, parent_url=None):
124            """walk through the tabs dictionary and build list of all tabs"""
125            tabs = []
126            for info in self._actionInfos(category, object):
127                icon = info['icon'] and '<img src="%s" />' % info['icon'] or ''
128                children = []
129                bottomLevel = self.conf.actions_tabs_level
130                if bottomLevel < 1 or level < bottomLevel:
131                    # try to find out appropriate subcategory
132                    subcat_id = self.cat_prefix + info['id'] + self.cat_sufix
133                    if subcat_id != info['id'] and \
134                       subcat_id in category.objectIds():
135                        subcat = category._getOb(subcat_id)
136                        if IActionCategory.providedBy(subcat):
137                            children = normalize_actions(subcat, object,
138                                                         level + 1,
139                                                         info['url'])
140
141                parent_id = category['id'].replace(self.cat_prefix,
142                                '').replace(self.cat_sufix, '')
143                tab = {'id': info['id'],
144                   'title': info['title'],
145                   'url': info['url'],
146                   'parent': (parent_id, parent_url)}
147                tabslist.append(tab)
148
149                tab = {'id': info['id'],
150                       'Title': info['title'],
151                       'Description': info['description'],
152                       'getURL': info['url'],
153                       'show_children': len(children) > 0,
154                       'children': children,
155                       'currentItem': False,
156                       'currentParent': False,
157                       'item_icon': {'html_tag': icon},
158                       'normalized_review_state': 'visible'}
159                tabs.append(tab)
160            return tabs
161        tabslist = []
162        tabs = normalize_actions(self.tool._getOb(self.conf.actions_category),
163                                 aq_inner(self.context), 0)
164        return tabs, tabslist
165
166    def _activate(self, res):
167        """Mark selected chain in the tabs dictionary"""
168        for info in res:
169            if info['getURL'] in self.id_chain:
170                info['currentItem'] = True
171                info['currentParent'] = True
172                if info['children']:
173                    self._activate(info['children'])
174
175    def mark_active(self, current_id, url):
176        for info in self.tabs:
177            if info['id'] == current_id and info['url'] == url:
178                self.mark_active(info['parent'][0], info['parent'][1])
179                self.id_chain.append(info['url'])
180
181    def _actionInfos(self, category, object, check_visibility=1,
182                     check_permissions=1, check_condition=1, max=-1):
183        """Return action infos for a given category"""
184        ec = self.tool._getExprContext(object)
185        actions = [ActionInfo(action, ec) for action in category.objectValues()
186                    if IAction.providedBy(action)]
187
188        action_infos = []
189        for ai in actions:
190            if check_visibility and not ai['visible']:
191                continue
192            if check_permissions and not ai['allowed']:
193                continue
194            if check_condition and not ai['available']:
195                continue
196            action_infos.append(ai)
197            if max + 1 and len(action_infos) >= max:
198                break
199        return action_infos
200
201    def _content_tabs(self):
202        """Return tree of tabs based on content structure"""
203        context = aq_inner(self.context)
204
205        queryBuilder = DropDownMenuQueryBuilder(context)
206        strategy = getMultiAdapter((context, None), INavtreeStrategy)
207        # XXX This works around a bug in plone.app.portlets which was
208        # fixed in http://dev.plone.org/svn/plone/changeset/18836
209        # When a release with that fix is made this workaround can be
210        # removed and the plone.app.portlets requirement in setup.py
211        # be updated.
212        if strategy.rootPath is not None and strategy.rootPath.endswith("/"):
213            strategy.rootPath = strategy.rootPath[:-1]
214
215        return buildFolderTree(context, obj=context, query=queryBuilder(),
216                               strategy=strategy).get('children', [])
217
218    @memoize
219    def _settings(self):
220        """Fetch dropdown menu settings registry"""
221        return getDropDownMenuSettings(self.context)
222
223    @ram.cache(menu_cache_key)
224    def createMenu(self):
225        html = self.recurse(children=self.portal_tabs, level=1)
226        return xhtmlslimmer.compress(html)
227
228    def _old_update(self):
229        context_state = getMultiAdapter((self.context, self.request),
230                                        name=u'plone_context_state')
231        actions = context_state.actions()
232        portal_tabs_view = getMultiAdapter((self.context, self.request),
233                                           name='portal_tabs_view')
234        self.portal_tabs = portal_tabs_view.topLevelTabs(actions=actions)
235
236        selectedTabs = self.context.restrictedTraverse('selectedTabs')
237        self.selected_tabs = selectedTabs('index_html',
238                                          self.context,
239                                          self.portal_tabs)
240        self.selected_portal_tab = self.selected_tabs['portal']
241
242    @memoize
243    def is_plone_four(self):
244        """Indicates if we are in plone 4.
245
246        """
247        pm = getToolByName(aq_inner(self.context), 'portal_migration')
248        try:
249            version = versionTupleFromString(pm.getSoftwareVersion())
250        except AttributeError:
251            version = versionTupleFromString(pm.getFileSystemVersion())
252
253        if version:
254            return version[0] == 4
Note: See TracBrowser for help on using the repository browser.