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

Last change on this file since 2843 was 2843, checked in by chervol, 14 years ago

added highlight exception for 'Home' tab

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