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

Last change on this file since 3153 was 3153, checked in by vmaksymiv, 13 years ago

pyflakes fixes

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