[Zope3-checkins] CVS: Zope3/src/zope/app/browser/services/configuration - __init__.py:1.1 changeconfigurations.pt:1.1 configure.zcml:1.1 editconfiguration.pt:1.1 namecomponentconfigurable.pt:1.1 nameconfigurable.pt:1.1 useconfiguration.pt:1.1

Jim Fulton jim@zope.com
Fri, 21 Mar 2003 16:09:35 -0500


Update of /cvs-repository/Zope3/src/zope/app/browser/services/configuration
In directory cvs.zope.org:/tmp/cvs-serv20505/src/zope/app/browser/services/configuration

Added Files:
	__init__.py changeconfigurations.pt configure.zcml 
	editconfiguration.pt namecomponentconfigurable.pt 
	nameconfigurable.pt useconfiguration.pt 
Log Message:
Refactored the module layout for general configuration views.
Moved the implementation into a separate configuration package.


=== Added File Zope3/src/zope/app/browser/services/configuration/__init__.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Gewneral configuration-related views

$Id: __init__.py,v 1.1 2003/03/21 21:09:33 jim Exp $
"""

from zope.app.browser.container.adding import Adding
from zope.app.browser.form.widget import BrowserWidget
from zope.app.interfaces.browser.form import IBrowserWidget
from zope.app.interfaces.container import IZopeContainer
from zope.app.interfaces.services.configuration import Active, Registered
from zope.app.interfaces.services.configuration import IComponentConfiguration
from zope.app.interfaces.services.configuration import Unregistered
from zope.app.interfaces.services.configuration import IConfigurationManager
from zope.app.interfaces.services.configuration import IUseConfiguration
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
from zope.app.traversing import getPath, traverse
from zope.component import getView, getServiceManager, getAdapter
from zope.proxy.context import getWrapperContainer, ContextWrapper
from zope.proxy.introspection import removeAllProxies
from zope.publisher.browser import BrowserView


class NameConfigurableView(BrowserView):

    indexMacros = index = ViewPageTemplateFile('nameconfigurable.pt')

    def update(self):

        names = list(self.context.listConfigurationNames())
        names.sort()

        items = []
        for name in names:
            registry = self.context.queryConfigurations(name)
            view = getView(registry, "ChangeConfigurations", self.request)
            view.setPrefix(name)
            view.update()
            cfg = registry.active()
            active = cfg is not None
            items.append(self._getItem(name, view, cfg))

        return items

    def _getItem(self, name, view, cfg):
        # hook for subclasses. returns a dict to append to an item
        return {"name": name,
                "active": cfg is not None,
                "inactive": cfg is None,
                "view": view,
                }


class NameComponentConfigurableView(NameConfigurableView):

    indexMacros = index = ViewPageTemplateFile('namecomponentconfigurable.pt')

    def _getItem(self, name, view, cfg):
        item_dict = NameConfigurableView._getItem(self, name, view, cfg)
        if cfg is not None:
            ob = traverse(cfg, cfg.componentPath)
            url = str(getView(ob, 'absolute_url', self.request))
        else:
            url = None
        item_dict['url'] = url
        return item_dict


class NameUseConfiguration:

    def __init__(self, context, request):
        self.context = context
        self.request = request

    def uses(self):
        component = self.context
        useconfig = getAdapter(component, IUseConfiguration)
        result = []
        for path in useconfig.usages():
            config = traverse(component, path)
            url = getView(config, 'absolute_url', self.request)
            result.append({'name': config.name,
                           'path': path,
                           'url': url(),
                           'status': config.status,
                           })
        return result


class ChangeConfigurations(BrowserView):

    _prefix = 'configurations'
    name = _prefix + ".active"
    message = ''
    configBase = ''

    def setPrefix(self, prefix):
        self._prefix = prefix
        self.name = prefix + ".active"

    def applyUpdates(self):
        message = ''
        if 'submit_update' in self.request.form:
            active = self.request.form.get(self.name)
            if active == "disable":
                active = self.context.active()
                if active is not None:
                    self.context.deactivate(active)
                    message = "Disabled"
            else:
                for info in self.context.info():
                    if info['id'] == active:
                        if not info['active']:
                            self.context.activate(info['configuration'])
                            message = "Updated"

        return message

    def update(self):

        message = self.applyUpdates()

        self.configBase = str(getView(getServiceManager(self.context),
                                      'absolute_url', self.request)
                              )

        configurations = self.context.info()

        # This is OK because configurations is just a list of dicts
        configurations = removeAllProxies(configurations)

        inactive = 1
        for info in configurations:
            if info['active']:
                inactive = None
            else:
                info['active'] = None

            info['summary'] = info['configuration'].implementationSummary()

        self.inactive = inactive
        self.configurations = configurations

        self.message = message


class ConfigurationStatusWidget(BrowserWidget):

    def __call__(self):
        checked = self._showData() or Unregistered
        result = [
            ('<label>'
             '<input type="radio" name="%s" value="%s"%s>'
             '&nbsp;'
             '%s'
             '</label>'
             % (self.name, v, (v == checked and ' checked' or ''), v)
             )
            for v in (Unregistered, Registered, Active)
            ]
        return ' '.join(result)


class ComponentPathWidget(BrowserWidget):
    """Widget for displaying component paths

    The widget doesn't actually allow editing. Rather it gets the
    value by inspecting its field's context. If the context is an
    IComponentConfiguration, then it just gets it's value from the
    component using the field's name. Otherwise, it uses the path to
    the context.
    """

    __implements__ =  IBrowserWidget


    def __call__(self):
        "See zope.app.interfaces.browser.form.IBrowserWidget"
        # Render as a link to the component
        field = self.context
        context = field.context 
        if IComponentConfiguration.isImplementedBy(context):
            # It's a configuration object. Just get the corresponsing attr
            path = getattr(context, field.__name__)
            component = traverse(context, path)
        else:
            # It must be a component that is about to be configured.
            component = context
            path = getPath(context)

        url = getView(component, 'absolute_url', self.request)

        return ('<a href="%s/@@SelectedManagementView.html">%s</a>'
                % (url, path))

    def hidden(self):
        "See zope.app.interfaces.browser.form.IBrowserWidget"
        return ''

    def getData(self):
        "See zope.app.interfaces.form.IWidget"
        field = self.context
        context = field.context 
        if IComponentConfiguration.isImplementedBy(context):
            # It's a configuration object. Just get the corresponsing attr
            path = getattr(context, self.__name__)
        else:
            # It must be a component that is about to be configured.
            path = getPath(context)

        return path

    def haveData(self):
        "See zope.app.interfaces.form.IWidget"
        return True


class AddComponentConfiguration(BrowserView):
    """View for adding component configurations

    This class is used to define configuration add forms.  It provides
    tha ``add`` and ``nextURL`` methods needed when creating add forms
    for non IAdding object. We need this here because configuration
    add forms are views of the component being configured.
    """
    
    def add(self, configuration):
        """Add a configuration

        We are going to add the configuration to the local
        configuration manager. We don't want to hard code the name of
        this, so we'll simply scan the containing folder and add the
        configuration to the first configuration manager we find.

        """

        component = self.context
        
        # Get the configuration manager for this folder
        folder = getWrapperContainer(component)
        for name in folder:
            item = folder[name]
            if IConfigurationManager.isImplementedBy(item):
                # We found one. Get it in context
                configure = traverse(folder, name)
                break
        else:
            raise SystemError("Couldn't find an configuration manager")

        # Adapt to IZopeContainer, which takes care of generating
        # standard events and calling standard hooks
        container = getAdapter(configure, IZopeContainer)

        # Now add the item, saving the key, which is picked by the config
        key = container.setObject("", configuration)

        # and return the config in context by fetching it from the container
        return container[key]

    def nextURL(self):
        return "@@useConfiguration.html"


class ConfigurationAdding(Adding):
    """Adding subclass for adding configurations."""

    menu_id = "add_configuration"

    def nextURL(self):
        return str(getView(self.context, "absolute_url", self.request))


class EditConfiguration(BrowserView):
    """A view on a configuration manager, used by configurations.pt."""

    def __init__(self, context, request):
        self.request = request
        self.context = context

    def update(self):
        """Perform actions depending on user input."""

        if 'keys' in self.request:
            k = self.request['keys']
        else:
            k = []

        msg = 'You must select at least one item to use this action'

        if 'remove_submit' in self.request:
            if not k: return msg
            self.remove_objects(k)
        elif 'top_submit' in self.request:
            if not k: return msg
            self.context.moveTop(k)
        elif 'bottom_submit' in self.request:
            if not k: return msg
            self.context.moveBottom(k)
        elif 'up_submit' in self.request:
            if not k: return msg
            self.context.moveUp(k)
        elif 'down_submit' in self.request:
            if not k: return msg
            self.context.moveDown(k)
        elif 'refresh_submit' in self.request:
            pass # Nothing to do

        return ''

    def remove_objects(self, key_list):
        """Remove the directives from the container."""
        container = getAdapter(self.context, IZopeContainer)
        for item in key_list:
            del container[item]

    def configInfo(self):
        """Render View for each directives."""
        result = []
        for name, configobj in self.context.items():
            configobj = ContextWrapper(configobj, self.context, name=name)
            url = str(getView(configobj, 'absolute_url', self.request))
            active = configobj.status == Active
            summary1 = getattr(configobj, "usageSummary", None)
            summary2 = getattr(configobj, "implementationSummary", None)
            item = {'name': name, 'url': url, 'active': active}
            if summary1:
                item['line1'] = summary1()
            if summary2:
                item['line2'] = summary2()
            result.append(item)
        return result


=== Added File Zope3/src/zope/app/browser/services/configuration/changeconfigurations.pt ===
<table width="100%">
  <tr tal:define="message view/message" tal:condition="message">
     <td></td>
     <td colspan="2"><em tal:content="message">xxxx</em></td>
  </tr>
  <tr tal:repeat="configuration view/configurations">
     <td><input type="radio" name="Roles" value="0"
             tal:attributes="
             name view/name;
             value configuration/id;
             checked configuration/active;
             "
             />
     </td>
     <td><a href="."
            tal:attributes="href string:${view/configBase}/${configuration/id}"
            tal:content="configuration/id"
         >foo/bar</a></td>
     <td tal:content="structure configuration/summary">
         Configuration summary
     </td>
  </tr>
  <tr>
     <td><input type="radio" name="Roles" value="disable"
                tal:attributes="
                   name view/name;
                   checked view/inactive;
                   "
                /></td>
     <td><em>Disable</em></td>
  </tr>
</table>


=== Added File Zope3/src/zope/app/browser/services/configuration/configure.zcml ===
<zopeConfigure xmlns='http://namespaces.zope.org/browser'>

<page
    for="zope.app.interfaces.services.configuration.IConfigurationStatus"
    name="edit"
    class=".ConfigurationStatusWidget"
    allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
    permission="zope.ManageServices"
    />

<page
    for="zope.app.interfaces.services.configuration.IConfigurationRegistry"
    name="ChangeConfigurations"
    template="changeconfigurations.pt"
    class=".ChangeConfigurations"
    allowed_interface="zope.app.interfaces.browser.form.IFormCollaborationView"
    permission="zope.ManageServices"
    />

<editform
    name="index.html"
    schema=
    "zope.app.interfaces.services.configuration.INamedComponentConfiguration."
    menu="zmi_views"
    label="Configuration"
    permission="zope.ManageServices"
    />

<page
    name="index.html" 
    for="zope.app.interfaces.services.configuration.INameComponentConfigurable"
    class=".NameComponentConfigurableView"
    permission="zope.ManageServices"
    attribute="index" 
    />

<page
    permission="zope.Public"
    allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
    for="zope.app.interfaces.services.configuration.IComponentPath"
    name="edit"
    class=".ComponentPathWidget" 
    />

<page
    permission="zope.Public"
    allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
    for="zope.app.interfaces.services.configuration.IComponentPath"
    name="display"
    class=".ComponentPathWidget" 
    />

<!-- ConfigurationManager -->

  <page
     name="index.html" 
     for="zope.app.interfaces.services.configuration.IConfigurationManager"
     menu="zmi_views" title="Configuration"
     permission="zope.ManageServices"
     class=".EditConfiguration"
     template="editconfiguration.pt" 
     />

  <view
     for="zope.app.interfaces.services.configuration.IConfigurationManager"
     name="+"
     permission="zope.ManageServices"
     class=".ConfigurationAdding">
    <page name="index.html"  attribute="index"  />
    <page name="action.html" attribute="action" />
  </view>

  <menuItem
        menu="add_component"
        for="zope.app.interfaces.container.IAdding"
        action="zope.app.services.ConfigurationManager"
        title="Configuration"
        />

</zopeConfigure>


=== Added File Zope3/src/zope/app/browser/services/configuration/editconfiguration.pt ===
<html metal:use-macro="views/standard_macros/page">
  <head>
    <title>View Service Configuration</title>
  </head>

  <body metal:fill-slot="body">

    <h2>Configuration Manager</h2>

    <form action="." method="POST"
          tal:define="message view/update"
          tal:attributes="action request/URL">

      <p tal:condition="message" tal:content="message" />

      <table>
        <thead>
          <tr>
            <th></th>
            <th align="left">Summary</th>
          </tr>
        </thead>
        <tbody>
          <tr tal:repeat="config view/configInfo">
            <td valign="top">
              <input type=checkbox name='keys:list' value='1'
                     tal:attributes="value config/name" />
            </td>
            <td>
              <a href="." tal:attributes="href config/name">
                <span tal:content="config/line1|default">
		  Config item <span tal:content="config/name" />
                </span>
              </a>
              <span tal:condition="not:config/active">(disabled)</span>
              <br>
              <span tal:content="config/line2|default">
                (No implementation summary)
              </span>
            </td>
          </tr>
        </tbody>
      </table>

      <div class="row">
        <input type=submit name='refresh_submit' value="Refresh">
        <input type=submit name='UPDATE_SUBMIT' value="Submit">
        <input type=submit name='remove_submit' value="Remove">
        &nbsp;&nbsp;
        <input type=submit name='top_submit' value="Top">
        <input type=submit name='up_submit' value="Up">
        <input type=submit name='down_submit' value="Down">
        <input type=submit name='bottom_submit' value="Bottom">
      </div>

    </form>

  </body>
</html>


=== Added File Zope3/src/zope/app/browser/services/configuration/namecomponentconfigurable.pt ===
<html metal:use-macro="views/standard_macros/page">
<div metal:fill-slot="body">
<div metal:define-macro="body">
<div tal:define="registries view/update">

  <h2 metal:define-slot="heading">Fruits configured in this fruits manager.</h2>

  <div tal:condition="not:registries">
       <p metal:define-slot="empty_text">No fruits have been configured</p>
  </div>

  <div tal:condition="registries">

    <div metal:define-slot="extra_top" tal:condition="nothing">

      <p>For each fruit, the fruit name is given and all of the components
         registered to provide the fruit are shown.  You may select the
         component to provide the fruit or disable the fruit.
      </p>

      <p>Select a fruit name or a component name to visit the fruit or
         component.
      </p>

    </div>

      <form action="." method="post" tal:attributes="action request/URL">

         <div tal:repeat="registry registries">
           <a href="#"
              tal:content="registry/name"
              tal:attributes="href registry/url"
              tal:condition="registry/active"
              >Orange</a>
           <span tal:replace="registry/name"
                 tal:condition="registry/inactive" />
           <br>
           <span tal:content="structure registry/view" />
         </div>

      <input type=submit name="submit_update" value="Update"><br>

      </form>

    <div metal:define-slot="extra_bottom" tal:condition="nothing">
    </div>

  </div>

</div>
</div>
</div>
</html>


=== Added File Zope3/src/zope/app/browser/services/configuration/nameconfigurable.pt ===
<html metal:use-macro="views/standard_macros/page">
<body metal:fill-slot="body">
<div metal:define-macro="body">
<div tal:define="registries view/update">

  <h2 metal:define-slot="heading">Fruits configured in this fruits manager.</h2>

  <div tal:condition="not:registries">
       <p metal:define-slot="empty_text">No fruits have been configured</p>
  </div>

  <div tal:condition="registries">

    <div metal:define-slot="extra_top">

      <p>For each fruit, the fruit name is given and all of the 
         registrations are shown.  You may select the
         registration to provide the fruit or disable the fruit.
      </p>

    </div>

      <form action="." method="post" tal:attributes="action request/URL">

      <table width="100%">

         <tr tal:repeat="registry registries">
           <td valign="top" align="right">
              <span
                 tal:content="registry/name"
                 tal:condition="registry/active"
                 >Orange</span>
              <span tal:replace="registry/name"
                    tal:condition="registry/inactive" />
           </td>
           <td tal:content="structure registry/view">
           </td>
         </tr>

      </table>

      <input type=submit name="submit_update" value="Update"><br>

      </form>

    <div metal:define-slot="extra_bottom" />

  </div>

  <p metal:define-slot="help_text">To configure a fruit, add a fruit component
     to a <em>package</em> in <a href="Packages">Packages</a> or to the <a
     href="Packages/default">default package</a>. After the fruit is added, add
     a fruit configuration that configures the component to provide a fruit.
     These instructions may not apply, depending what kind of fruit you have.
  </p>

</div>
</div>
</body>
</html>


=== Added File Zope3/src/zope/app/browser/services/configuration/useconfiguration.pt ===
<html metal:use-macro="context/@@standard_macros/page">
  <body>
    <div metal:fill-slot="body">

      <p>Configurations for this object:</p>

      <ul>

	<li tal:repeat="use view/uses">

	  <a href="http://."
	     tal:attributes="href use/url"
	     tal:content="use/name">
	   Example Service
	   </a> (<span tal:replace="use/status">Active</span>)

	</li>
      </ul>

      <p><a href="addConfiguration.html">Add a configuration for this object</a>

    </div>
  </body>
</html>