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

Last change on this file since 54 was 54, checked in by crchemist, 19 years ago

Added ability to genarate sitemap even googlesitemap_properties sheet is absent

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