def testSelectedSkinHasProperCSSClass(self):
     st = getToolByName(self.folder, "portal_skins")
     skins = st.getSkinSelections()
     actions = self.menu.getMenuItems(self.folder, self.request)
     action = [a for a in actions if a["title"] == skins[0]][0]
     self.assertEqual("actionMenu", action["extra"]["class"])
     set_selected_default_skin(self.folder, skins[0])
     self.assertEqual(skins[0], get_selected_default_skin(self.folder))
     actions = self.menu.getMenuItems(self.folder, self.request)
     action = [a for a in actions if a["title"] == skins[0]][0]
     self.assertEqual("actionMenuSelected", action["extra"]["class"])
    def update(self):
        """Set selected skin as the default for the current folder."""
        context = aq_inner(self.context)
        utils = getToolByName(context, "plone_utils")

        # Which skin is requested?
        skin_name = self.request.form.get("skin_name", None)
        if skin_name is not None:
            skins_tool = getToolByName(context, 'portal_skins')
            if skin_name not in skins_tool.getSkinSelections():
                skin_name = None

        # Which skin is currently used as default skin, if any?
        current_skin = get_selected_default_skin(context)

        # Determine what needs to be done, and create or remove a
        # local site hook when needed.
        if skin_name is None and current_skin is None:
            utils.addPortalMessage(_(u"Nothing changed."))
        elif skin_name == current_skin:
            utils.addPortalMessage(_(u"Nothing changed."))
        elif skin_name is None and current_skin is not None:
            # Need to remove the hook.
            utils.addPortalMessage(_(u"No default skin selected anymore."))
            remove_hook(context)
        else:
            # The normal case: a change to the default skin.
            utils.addPortalMessage(_(u"Skin changed."))
            add_hook(context)

        # Finally set the default skin.  Note that this is safe to
        # call when skin_name is None as well, as this cleans up a
        # possible earlier setting.
        set_selected_default_skin(context, skin_name)

        return self.request.RESPONSE.redirect(context.absolute_url())
    def available(self):
        if self.context_state.is_portal_root():
            # Just use the portal_skins tool, Luke!
            return False

        # This menu is also used to set the navigation root, when
        # allowed.
        if self._allowSetNavigationRoot():
            return True

        if not self._manageSkinSettings():
            return False

        # Only allow this menu on folders.
        if not (self.context_state.is_structural_folder()
                or self.context_state.is_default_page()):
            return False

        # Check if our property sheet is available.  When not, then
        # this might be a second Plone site in the same Zope instance.
        # If we are not installed in this Plone Site, we do not want
        # to offer this menu item.
        if not self.tools.properties().get('editskin_switcher'):
            return False

        if get_selected_default_skin(self.folder):
            # We have previously selected a default skin, so we should
            # show the menu to make this clear (and possibly unset
            # it).
            return True

        skins_tool = getToolByName(self.context, 'portal_skins')
        if len(skins_tool.getSkinSelections()) < 2:
            # Nothing to choose.
            return False
        return True
def switch_skin(object, event):
    """Switch to the Sunburst Theme skin when we are editing.

    Note: when we bail out before the changeSkin call, then we show
    the normal theme, which presumably is a custom theme for this
    website.

    If we do the changeSkin call, this means we switch to the edit
    skin, which normally is the Sunburst Theme skin.
    """
    request = event.request
    context = get_real_context(object)
    current_skin = context.getCurrentSkinName()
    skin_name = get_selected_default_skin(context)
    if skin_name is not None and not request.get('editskinswitched'):
        # We've specified a skin and are not in the edit skin.
        portal_skins = getToolByName(context, 'portal_skins', None)
        if (portal_skins is not None and
                skin_name not in portal_skins.getSkinSelections()):
            logger.warn("Non-existing skin %s set on %s",
                        skin_name, context.absolute_url())
        else:
            context.changeSkin(skin_name, request)
            set_theme_specific_layers(request, context, skin_name,
                                      current_skin)

    portal_props = getToolByName(context, 'portal_properties', None)
    if portal_props is None:
        return None
    editskin_props = portal_props.get('editskin_switcher')
    if editskin_props is None:
        return None

    # Okay, we have a property sheet we can use.
    edit_skin = editskin_props.getProperty('edit_skin', '')

    if force_login(request, editskin_props):
        # We have a header that forces us to be logged in; so add a
        # hook at the end of the traversal to check that we really are
        # logged in.
        request.post_traverse(check_auth, (request, ))

    # Check if we need authentication first, possibly in addition to
    # one of the other tests
    if need_authentication(request, editskin_props) and anonymous(request):
        logger.debug("need auth, but am anonymous: staying at normal skin.")
        return None

    # Try to find a reason for switching to the edit skin.  When one
    # of the selected actions returns True, we switch the skin.
    switches = editskin_props.getProperty('switch_skin_action', ())
    if not isinstance(switches, tuple):
        # Old data using a selection instead of multiple selection,
        # which returns a string instead of a tuple of strings.
        switches = (switches, )

    found = False
    for switch in switches:
        method = methods.get(switch)
        if not method:
            continue
        if method(request, editskin_props):
            found = True
            break
    if not found:
        # No switching
        logger.debug("no switching, staying at normal skin")
        return None

    logger.debug("will switch to edit skin")

    # Use to preview default skin in edit skin mode
    if request.get('mutate_skin', '') == 'default':
        return None

    # Assume that if you get here you are switching to the edit skin
    # ... flag this for the purposes of caching / kss loading etc.
    request.set('editskinswitched', 1)

    # If the edit_skin does not exist, the next call is
    # intelligent enough to use the default skin instead.
    context.changeSkin(edit_skin, request)
    set_theme_specific_layers(request, context, edit_skin, current_skin)
    return None
    def getMenuItems(self, context, request):
        """Return menu item entries in a TAL-friendly form."""
        results = []

        context_state = getMultiAdapter((context, request),
                                        name='plone_context_state')
        folder = context
        if not context_state.is_structural_folder():
            folder = utils.parent(context)
        url = folder.absolute_url()
        current_skin = get_selected_default_skin(folder)

        skins_tool = getToolByName(context, "portal_skins")
        skin_selections = skins_tool.getSkinSelections()

        # Only add menu items for skins when we have a choice or when
        # we have previously selected a default skin.  It could be
        # that this default skin has been removed and then we need a
        # way to unset it.
        tools = getMultiAdapter((context, request), name='plone_tools')
        if tools.membership().checkPermission(SetDefaultSkin, folder) and (
                len(skin_selections) > 1 or current_skin):
            if current_skin and current_skin not in skin_selections:
                # Skin has been removed.
                skin = current_skin
                skin_title = utils.safe_unicode(skin)
                skin_id = utils.normalizeString(skin, folder, "utf-8")
                results.append(
                    {"title": _(u"Warning: ${skin}",
                                mapping={'skin': skin_title}),
                     "description": _(
                         u"Skin '${skin}' no longer exists. Selecting this "
                         u"again will result in using the site default.",
                         mapping=dict(skin=skin_title)),
                     "action": "%s/@@switchDefaultSkin?skin_name=%s" % (
                         url, skin),
                     "selected": True,
                     "extra": {
                         "is_skin_option": True,
                         "id": "collective.editskinswitcher-skin-%s" % skin_id,
                         "separator": False,
                         "class": 'actionMenuSelected'},
                     "submenu": None,
                     "icon": None,
                     })

            for skin in skin_selections:
                skin_id = utils.normalizeString(skin, folder, "utf-8")
                skin_title = utils.safe_unicode(skin)
                selected = skin == current_skin
                cssClass = selected and "actionMenuSelected" or "actionMenu"
                results.append(
                    {"title": skin,
                     "description": _(u"Use '${skin}' skin for this folder",
                                      mapping=dict(skin=skin_title)),
                     "action": "%s/@@switchDefaultSkin?skin_name=%s" % (
                         url, skin),
                     "selected": selected,
                     "extra": {
                         "is_skin_option": True,
                         "id": "collective.editskinswitcher-skin-%s" % skin_id,
                         "separator": False,
                         "class": cssClass},
                     "submenu": None,
                     "icon": None,
                     })

        # Add option to reset the default.
        if current_skin:
            # Use a fake id that is unlikely to be the id of an actual skin.
            skin_id = 'collective_set_default_editor_use_site_default'
            results.append(
                {"title": _(u"Use site default"),
                 "description": u"",
                 "action": "%s/@@switchDefaultSkin?skin_name=%s" % (
                     url, skin_id),
                 "selected": False,
                 "extra": {
                     "is_skin_option": True,
                     "id": "collective.editskinswitcher-skin-%s" % skin_id,
                     "separator": 'actionSeparator',
                     "class": 'actionMenu'},
                 "submenu": None,
                 "icon": None,
                 })

        if tools.membership().checkPermission(SetNavigationRoot, folder):
            # Now add an option to set/unset the navigation root.
            menu_item = {
                "title": _(u"Navigation root"),
                "extra": {
                    "is_skin_option": False,
                    "id": "collective.editskinswitcher-set-navigation-root",
                    "separator": 'actionSeparator',
                    },
                "submenu": None,
                "icon": None,
                }
            if INavigationRoot.providedBy(folder):
                menu_item["selected"] = True
                menu_item["cssClass"] = "actionMenuSelected"
                menu_item["description"] = _(
                    u"No longer use this folder as a navigation root.")
                menu_item["action"] = "%s/@@unset-navigation-root" % (url)
            else:
                menu_item["selected"] = False
                menu_item["cssClass"] = "actionMenu"
                menu_item["description"] = _(
                    u"Start using this folder as a navigation root.")
                menu_item["action"] = "%s/@@set-navigation-root" % (url)
            results.append(menu_item)

        return results