source: products/qPloneTabs/branches/quintagroup.plonetabs/trunk/quintagroup/plonetabs/browser/plonetabs.py @ 53

Last change on this file since 53 was 53, checked in by crchemist, 18 years ago

Code cleanup

  • Property svn:eol-style set to native
File size: 19.9 KB
Line 
1import copy
2
3from Acquisition import aq_inner
4
5from zope.interface import implements
6from zope.component import getUtility, getMultiAdapter
7from zope.i18n import translate
8from zope.schema.interfaces import IVocabularyFactory
9from zope.exceptions import UserError
10
11from Products.CMFCore.utils import getToolByName
12from Products.CMFCore.interfaces import IAction, IActionCategory
13from Products.CMFCore.ActionInformation import Action, ActionCategory
14from Products.CMFEditions.setuphandlers import DEFAULT_POLICIES
15from Products.CMFPlone import PloneMessageFactory as _
16from Products.CMFPlone import PloneMessageFactory as pmf
17from Products.CMFPlone import utils
18from Products.CMFPlone.browser.navigation import get_view_url
19from Products.Five.browser import BrowserView
20from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
21from Products.statusmessages.interfaces import IStatusMessage
22
23from plone.app.layout.navigation.root import getNavigationRoot
24from plone.app.kss.plonekssview import PloneKSSView
25from plone.app.workflow.remap import remap_workflow
26from plone.memoize.instance import memoize
27from kss.core import kssaction, KSSExplicitError
28
29from quintagroup.plonetabs.config import *
30from interfaces import IPloneTabsControlPanel
31
32ACTION_ATTRS = ["id", "visible", "description", "url_expr", "title", "available_expr"]
33
34class PloneTabsControlPanel(PloneKSSView):
35   
36    implements(IPloneTabsControlPanel)
37   
38    template = ViewPageTemplateFile("templates/plonetabs.pt")
39    actionslist_template = ViewPageTemplateFile("templates/actionslist.pt")
40    autogenerated_template = ViewPageTemplateFile("templates/autogenerated.pt")
41    sections_template = ViewPageTemplateFile("templates/sections.pt")
42   
43    def __call__(self):
44        """ Perform the update and redirect if necessary, or render the page """
45        postback = True
46        errors = {}
47        context = aq_inner(self.context)
48       
49        form = self.request.form
50        action = form.get("action", "")
51        submitted = form.get('form.submitted', False)
52       
53        # action handler def handler(self, form)
54        if action == "add_action":
55            if submitted:
56                postback = self.manage_addAction(form, errors)
57        elif action == "edit_action":
58            if submitted:
59                pass
60        elif action == "delete_action":
61            postback = self.manage_deleteAction(self.request, errors)
62        #elif action == "visible_action":
63                #pass
64        elif action == "move_action":
65            pass
66        elif action == "set_autogeneration":
67            if submitted:
68                postback = self.manage_setAutogeneration(form, errors)
69       
70        if postback:
71            return self.template(errors=errors)
72   
73    ########################################
74    # Methods for processing configlet posts
75    ########################################
76   
77    def manage_setAutogeneration(self, form, errors):
78        """ Process managing autogeneration settings """
79       
80        # set excludeFromNav property for root objects
81        portal = getMultiAdapter((aq_inner(self.context), self.request), name='plone_portal_state').portal()
82        generated_tabs = form.get("generated_tabs", '0')
83        nonfolderish_tabs = form.get("nonfolderish_tabs", '0')
84       
85        for item in self.getRootTabs():
86            obj = getattr(portal, item['id'], None)
87            if obj is not None:
88                checked = form.get(item['id'], None)
89                if checked == '1':
90                    obj.update(excludeFromNav=False)
91                else:
92                    obj.update(excludeFromNav=True)
93
94        # set disable_folder_sections property
95        changeProperties = getToolByName(self.context, "portal_properties").site_properties.manage_changeProperties
96       
97        if int(generated_tabs) == 1:
98            changeProperties(disable_folder_sections=False)
99        else:
100            changeProperties(disable_folder_sections=True)
101       
102        # set disable_nonfolderish_sections property
103        if int(nonfolderish_tabs) == 1:
104            changeProperties(disable_nonfolderish_sections=False)
105        else:
106            changeProperties(disable_nonfolderish_sections=True)
107       
108        self.redirect()
109       
110        return False
111   
112    def manage_addAction(self, form, errors):
113        """ Add a new action to given category, if category doesn't exist, create it """
114       
115        # extract data from request's form
116        id = form.get("id")
117        category = form.get("category")
118       
119        # before checking for existence category we will validate all input data
120        # and issue errors if needed
121       
122        # create and validate action
123        if not id:
124            errors["id"] = _(u"Id field is required")
125        if not form.get("title"):
126            errors["title"] = _(u"Title field is required")
127
128        action = Action(id)
129        for prop in ACTION_ATTRS:
130            if prop != "id":
131                try:
132                    if prop == "visible":
133                        value = int(form.get(prop, '0'))
134                    else:
135                        value = form.get(prop)
136                   
137                    action._setPropValue(prop, value)
138                except Exception, e:
139                    errors[prop] = _(u"%s" % str(e))
140       
141        # if not errors find (or create) category and set action to it
142        if not errors:
143            portal_actions = getToolByName(self.context, "portal_actions")
144            cat_container = None
145           
146            if category not in map(lambda x: x.id, filter(lambda x: IActionCategory.providedBy(x), portal_actions.objectValues())):
147                try:
148                    portal_actions._setObject(category, ActionCategory(category))
149                except Exception, e:
150                    errors["select_category"] = _(u"%s" % str(e))
151                else:
152                    cat_container = portal_actions[category]
153            else:
154                cat_container = portal_actions[category]
155           
156            if cat_container is not None:
157                try:
158                    cat_container._setObject(id, action)
159                except Exception, e:
160                    errors["id"] = _(u"%s" % str(e))
161       
162        if not errors:
163            self.redirect(search="category=%s" % category)
164            return False
165        else:
166            IStatusMessage(self.request).addStatusMessage(_(u"Please correct the indicated errors."), type="error")
167            return True
168   
169    def manage_deleteAction(self, request, errors):
170        """ Server view for deletign action with given id/category """
171        portal_actions = getToolByName(self.context, "portal_actions")
172
173        id = request.get("id", "")
174        category = request.get("category", "")
175       
176        if category not in portal_actions.objectIds():
177            IStatusMessage(self.request).addStatusMessage(_(u"Unexistent root portal actions category '%s'" % category), type="error")
178        else:
179            cat_container = portal_actions[category]
180            if id not in map(lambda x: x.id, filter(lambda x: IAction.providedBy(x), cat_container.objectValues())):
181                IStatusMessage(self.request).addStatusMessage(_(u"'%s' action does not exist in '%s' category" % (id, category)), type="error")
182            else:
183                cat_container.manage_delObjects(ids=[id,])
184                IStatusMessage(self.request).addStatusMessage(_(u"'%s' action in '%s' category successfuly deleted" % (id, category)), type="info")
185       
186        self.redirect(search="category=%s" % category)
187        return False
188   
189    def redirect(self, url="", search="", hash=""):
190        """ Redirect to @@plonetabs-controlpanel configlet """
191       
192        if url == "":
193            portal_url =  getMultiAdapter((self.context, self.request), name=u"plone_portal_state").portal_url()
194            url = "%s/%s" % (portal_url, "@@plonetabs-controlpanel")
195       
196        if search != "":
197            search = "?%s" % search
198       
199        if hash != "":
200            hash = "#%s" % hash
201       
202        self.request.response.redirect("%s%s%s" % (url, search, hash))
203   
204   
205    ###################################
206    ##  Methods - providers for templates
207    ###################################
208   
209    def getPageTitle(self, category="portal_tabs"):
210        """ See interface """
211        portal_props = getToolByName(self.context, "portal_properties")
212        default_title = "Plone '%s' Configuration" % category
213       
214        if not hasattr(portal_props, PROPERTY_SHEET):
215            return default_title
216       
217        sheet = getattr(portal_props, PROPERTY_SHEET)
218        if not hasattr(sheet, FIELD_NAME):
219            return default_title
220       
221        field = sheet.getProperty(FIELD_NAME)
222        dict = {}
223        for line in field:
224            cat, title = line.split("|", 2)
225            dict[cat] = title
226       
227        return dict.get(category, None) or default_title
228   
229    def hasActions(self, category="portal_tabs"):
230        """ See interface """
231        return len(getToolByName(self.context, "portal_actions").listActions(categories=[category,])) > 0
232   
233    def getPortalActions(self, category="portal_tabs"):
234        """ See interface """
235        portal_actions = getToolByName(self.context, "portal_actions")
236       
237        if category not in portal_actions.objectIds():
238            return []
239       
240        actions = []
241        for item in portal_actions[category].objectValues():
242            if IAction.providedBy(item):
243                actions.append(item)
244       
245        return actions
246   
247    def isGeneratedTabs(self):
248        """ See interface """
249        site_properties = getToolByName(self.context, "portal_properties").site_properties
250        return not site_properties.getProperty("disable_folder_sections", False)
251   
252    def isNotFoldersGenerated(self):
253        """ See interface """
254        site_properties = getToolByName(self.context, "portal_properties").site_properties
255        return not site_properties.getProperty("disable_nonfolderish_sections", False)
256   
257    def getActionsList(self, category="portal_tabs"):
258        """ See interface """
259        return self.actionslist_template(category=category)
260   
261    def getGeneratedTabs(self):
262        """ See interface """
263        return self.autogenerated_template()
264   
265    def getRootTabs(self):
266        """ See interface """
267        context = aq_inner(self.context)
268       
269        portal_catalog = getToolByName(context, 'portal_catalog')
270        portal_properties = getToolByName(context, 'portal_properties')
271        navtree_properties = getattr(portal_properties, 'navtree_properties')
272       
273        # Build result dict
274        result = []
275       
276        # check whether we only want actions
277        if not self.isGeneratedTabs():
278            return result
279       
280        query = {}
281       
282        rootPath = getNavigationRoot(context)
283        query['path'] = {'query' : rootPath, 'depth' : 1}
284        query['portal_type'] = utils.typesToList(context)
285       
286        sortAttribute = navtree_properties.getProperty('sortAttribute', None)
287        if sortAttribute is not None:
288            query['sort_on'] = sortAttribute
289           
290            sortOrder = navtree_properties.getProperty('sortOrder', None)
291            if sortOrder is not None:
292                query['sort_order'] = sortOrder
293       
294        if navtree_properties.getProperty('enable_wf_state_filtering', False):
295            query['review_state'] = navtree_properties.getProperty('wf_states_to_show', [])
296       
297        query['is_default_page'] = False
298
299        if not self.isNotFoldersGenerated():
300            query['is_folderish'] = True
301
302        # Get ids not to list and make a dict to make the search fast
303        idsNotToList = navtree_properties.getProperty('idsNotToList', ())
304        excludedIds = {}
305        for id in idsNotToList:
306            excludedIds[id]=1
307
308        rawresult = portal_catalog.searchResults(**query)
309
310        # now add the content to results
311        for item in rawresult:
312            if not excludedIds.has_key(item.getId):
313                id, item_url = get_view_url(item)
314                data = {'name'       : utils.pretty_title_or_id(context, item),
315                        'id'         : id,
316                        'url'        : item_url,
317                        'description': item.Description,
318                        'exclude_from_nav' : item.exclude_from_nav}
319                result.append(data)
320       
321        return result
322   
323    def getCategories(self):
324        """ See interface """
325        portal_actions = getToolByName(self.context, "portal_actions")
326        return portal_actions.objectIds()
327   
328    def test(self, condition, ifTrue, ifFalse):
329        """ See interface """
330        if condition:
331            return ifTrue
332        else:
333            return ifFalse
334   
335    # methods for rendering global-sections viewlet via kss,
336    # due to bug in macroContent when global-section list is empty,
337    # ul have condition
338    def portal_tabs(self):
339        """ See global-sections viewlet """
340        actions = context_state = getMultiAdapter((self.context, self.request), name=u"plone_context_state").actions()
341        portal_tabs_view = getMultiAdapter((self.context, self.request), name="portal_tabs_view")
342       
343        return portal_tabs_view.topLevelTabs(actions=actions)
344   
345    def selected_portal_tab(self):
346        """ See global-sections viewlet """
347        selectedTabs = self.context.restrictedTraverse('selectedTabs')
348        selected_tabs = selectedTabs('index_html', self.context, self.portal_tabs())
349       
350        return selected_tabs['portal']
351   
352    ##########################
353    # kss server actions
354    ##########################
355   
356    def updateGlobalSections(self, ksscore):
357        """ Method for updating global-sections on client """
358        ksscore.replaceHTML(
359            ksscore.getHtmlIdSelector("portal-globalnav"),
360            self.sections_template(),
361            withKssSetup="False")
362   
363   
364    # XXX TODO
365    #def updateSection(self, ksscore, section):
366        #""" Method for updating global-sections on client """
367       
368        #replace_id = section
369        #macro = SECTION_MAPPING.get(section, None)
370       
371        #if macro is not None:
372            #ksscore.replaceHTML(
373                #ksscore.getHtmlIdSelector(replace_id),
374                #self.macroContent(macro),
375                ##self.sections_template(),
376                #withKssSetup="False")
377   
378    def validateAction(self, id, category, prefix="tabslist_"):
379        """ If action with given id and category doesn't exist - raise kss exception """
380        portal_actions = getToolByName(self.context, "portal_actions")
381       
382        # remove prefix, added for making ids on configlet unique ("tabslist_")
383        act_id = id[len("tabslist_"):]
384       
385        if category not in portal_actions.objectIds():
386            raise KSSExplicitError, "Unexistent root portal actions category %s" % category
387       
388        cat_container = portal_actions[category]
389        if act_id not in map(lambda x: x.id, filter(lambda x: IAction.providedBy(x), cat_container.objectValues())):
390            raise KSSExplicitError, "%s action does not exist in %s category" % (act_id, category)
391       
392        return (cat_container, act_id)
393   
394    @kssaction
395    def toggleGeneratedTabs(self, field, checked='0'):
396        """ Toggle autogenaration setting on configlet """
397       
398        changeProperties = getToolByName(self.context, "portal_properties").site_properties.manage_changeProperties
399        if checked == '1':
400            changeProperties(**{field : False})
401        else:
402            changeProperties(**{field : True})
403       
404        ksscore = self.getCommandSet("core")
405        replace_id = "roottabs"
406        content = self.getGeneratedTabs()
407       
408        ksscore.replaceInnerHTML(ksscore.getHtmlIdSelector(replace_id), content, withKssSetup="True")
409       
410        # update global-sections viewlet
411        self.updateGlobalSections(ksscore)
412   
413    @kssaction
414    def toggleActionsVisibility(self, id, checked='0', category=None):
415        """ Toggle visibility for portal actions """
416        portal_actions = getToolByName(self.context, "portal_actions")
417        cat_container, act_id = self.validateAction(id, category)
418       
419        if checked == '1':
420            checked = True
421        else:
422            checked = False
423       
424        cat_container[act_id].visible = checked
425       
426        ksscore = self.getCommandSet("core")
427        if checked:
428            ksscore.removeClass(ksscore.getHtmlIdSelector(id), value="invisible")
429        else:
430            ksscore.addClass(ksscore.getHtmlIdSelector(id), value="invisible")
431       
432        # update global-sections viewlet
433        if category == "portal_tabs":
434            self.updateGlobalSections(ksscore)
435   
436    @kssaction
437    def toggleRootsVisibility(self, id, checked='0'):
438        """ Toggle visibility for portal root objects (exclude_from_nav) """
439        portal = getMultiAdapter((aq_inner(self.context), self.request), name='plone_portal_state').portal()
440       
441        # remove prefix, added for making ids on configlet unique ("roottabs_")
442        obj_id = id[len("roottabs_"):]
443       
444        if obj_id not in portal.objectIds():
445            raise KSSExplicitError, "Object with %s id doesn't exist in portal root" % obj_id
446       
447        if checked == '1':
448            checked = True
449        else:
450            checked = False
451       
452        portal[obj_id].update(excludeFromNav=not checked)
453       
454        ksscore = self.getCommandSet("core")
455        if checked:
456            ksscore.removeClass(ksscore.getHtmlIdSelector(id), value="invisible")
457        else:
458            ksscore.addClass(ksscore.getHtmlIdSelector(id), value="invisible")
459       
460        # update global-sections viewlet
461        self.updateGlobalSections(ksscore)
462   
463    @kssaction
464    def deleteAction(self, id, category):
465        """ Delete portal action with given id & category """
466        portal_actions = getToolByName(self.context, "portal_actions")
467        cat_container, act_id = self.validateAction(id, category)
468       
469        cat_container.manage_delObjects(ids=[act_id,])
470       
471        # update action list on client
472        ksscore = self.getCommandSet("core")
473       
474        ksscore.deleteNode(ksscore.getHtmlIdSelector(id))
475       
476        # add "noitems" class to Reorder controls to hide it
477        if not filter(lambda x: IAction.providedBy(x), cat_container.objectValues()):
478            ksscore.addClass(ksscore.getHtmlIdSelector("reorder"), value="noitems")
479       
480        # XXX TODO: fade effect during removing, for this kukit js action/command plugin needed
481       
482        # update global-sections viewlet
483        if category == "portal_tabs":
484            self.updateGlobalSections(ksscore)
485   
486    @kssaction
487    def editAction(self, id, category):
488        """ Show edit form for given action """
489        cat_container, act_id = self.validateAction(id, category)
490       
491        # collect data
492        action_info = self.copyAction(cat_container[act_id])
493        action_info["editing"] = True
494       
495        ksscore = self.getCommandSet("core")
496        content = self.actionslist_template(tabs=[action_info,])
497        replace_id = id
498       
499        ksscore.replaceHTML(ksscore.getHtmlIdSelector(replace_id), content)
500       
501        # focus name field
502        ksscore.focus(ksscore.getCssSelector("#%s input[name=name_%s]" % (id, act_id)))
503   
504    @kssaction
505    def editCancel(self, id, category):
506        """ Hide edit form for given action """
507        cat_container, act_id = self.validateAction(id, category)
508       
509        ksscore = self.getCommandSet("core")
510        content = self.actionslist_template(tabs=[cat_container[act_id],])
511        replace_id = id
512       
513        ksscore.replaceHTML(ksscore.getHtmlIdSelector(replace_id), content)
514   
515    # Utility Methods
516   
517    def copyAction(self, action):
518        """ Copyt action to dictionary """
519        action_info = {}
520        for attr in ACTION_ATTRS:
521            action_info[attr] = getattr(action, attr)
522        return action_info
523   
524
525
526
527
528
529
530
531
532
533
Note: See TracBrowser for help on using the repository browser.