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

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

pep8 fixes

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