[Zope3-checkins] CVS: Zope3/src/zope/app/browser/services/registration - __init__.py:1.1 changeregistrations.pt:1.1 configure.zcml:1.1 editregistration.pt:1.1 namecomponentregistry.pt:1.1 nameregistry.pt:1.1 registered.pt:1.1

Jim Fulton jim@zope.com
Sat, 21 Jun 2003 17:22:04 -0400


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

Added Files:
	__init__.py changeregistrations.pt configure.zcml 
	editregistration.pt namecomponentregistry.pt nameregistry.pt 
	registered.pt 
Log Message:
Major refactoring to reflect change in terminology from
"configuration" to "registration" to refer to the configuration of how
objects are used (as opposed to their internal configuration).


=== Added File Zope3/src/zope/app/browser/services/registration/__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 registry-related views

$Id: __init__.py,v 1.1 2003/06/21 21:22:02 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.registration import RegisteredStatus
from zope.app.interfaces.services.registration import ActiveStatus
from zope.app.interfaces.services.registration import IComponentRegistration
from zope.app.interfaces.services.registration import UnregisteredStatus
from zope.app.interfaces.services.registration import IRegistered
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
from zope.app.traversing import getPath, getName, traverse
from zope.component import getView, getServiceManager, getAdapter
from zope.context import getWrapperContainer
from zope.app.context import ContextWrapper
from zope.proxy import removeAllProxies
from zope.publisher.browser import BrowserView
from zope.interface import implements


class NameRegistryView(BrowserView):

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

    def update(self):

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

        items = []
        for name in names:
            registry = self.context.queryRegistrations(name)
            view = getView(registry, "ChangeRegistrations", 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 NameComponentRegistryView(NameRegistryView):

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

    def _getItem(self, name, view, cfg):
        item_dict = NameRegistryView._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 NameRegistered:

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

    def uses(self):
        component = self.context
        useconfig = getAdapter(component, IRegistered)
        result = []
        for path in useconfig.usages():
            config = traverse(component, path)
            description = None
            summaryMethod = getattr(config, "usageSummary", None)
            if summaryMethod:
                description = summaryMethod()
            url = getView(config, 'absolute_url', self.request)
            # XXX This assumes the registration implements
            #     INamedComponentRegistration rather than just
            #     IComponentRegistration.  ATM there are no
            #     counterexamples, so this is a sleeper bug;
            #     but what to do?  Could move the registration
            #     management up to INamedComponentRegistration,
            #     or could use path as default for name here.
            result.append({'name': config.name,
                           'path': path,
                           'url': url(),
                           'status': config.status,
                           'description': description or config.name,
                           })
        return result


class ChangeRegistrations(BrowserView):

    _prefix = 'registrations'
    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['registration'])
                            message = "Updated"

        return message

    def update(self):

        message = self.applyUpdates()

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

        registrations = self.context.info()

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

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

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

        self.inactive = inactive
        self.registrations = registrations

        self.message = message


class RegistrationStatusWidget(BrowserWidget):

    def __call__(self):
        checked = self._showData() or UnregisteredStatus
        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 (UnregisteredStatus, RegisteredStatus, ActiveStatus)
            ]
        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
    IComponentRegistration, then it just gets its 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 IComponentRegistration.isImplementedBy(context):
            # It's a registration object. Just get the corresponding attr
            path = getattr(context, field.__name__)
            # The path may be relative; then interpret relative to ../..
            if not path.startswith("/"):
                context = traverse(context, "../..")
            component = traverse(context, path)
        else:
            # It must be a component that is about to be configured.
            component = context
            # Always use a relative path (just the component name)
            path = getName(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 IComponentRegistration.isImplementedBy(context):
            # It's a registration object. Just get the corresponding attr
            # XXX this code has no unittests !!!
            path = getattr(context, field.__name__)
        else:
            # It must be a component that is about to be configured.
            # Always return a relative path (just the component name)
            path = getName(context)

        return path

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


class AddComponentRegistration(BrowserView):
    """View for adding component registrations

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

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

        """

        component = self.context
        
        # Get the registration manager for this folder
        folder = getWrapperContainer(component)
        configure = folder.getRegistrationManager()

        # 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("", registration)

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

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


class RegistrationAdding(Adding):
    """Adding subclass for adding registrations."""

    menu_id = "add_registration"

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


class EditRegistration(BrowserView):
    """A view on a registration manager, used by registrations.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 == ActiveStatus
            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/registration/changeregistrations.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="registration view/registrations">
     <td><input type="radio" name="Roles" value="0"
             tal:attributes="
             name view/name;
             value registration/id;
             checked registration/active;
             "
             />
     </td>
     <td><a href="."
            tal:attributes="href string:${view/configBase}/${registration/id}"
            tal:content="registration/id"
         >foo/bar</a></td>
     <td tal:content="structure registration/summary">
         Registration 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/registration/configure.zcml ===
<zopeConfigure xmlns='http://namespaces.zope.org/browser'>

<page
    for="zope.app.interfaces.services.registration.IRegistrationStatus"
    name="edit"
    class=".RegistrationStatusWidget"
    allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
    permission="zope.ManageServices"
    />

<page
    for="zope.app.interfaces.services.registration.IRegistrationStack"
    name="ChangeRegistrations"
    template="changeregistrations.pt"
    class=".ChangeRegistrations"
    allowed_interface="zope.app.interfaces.browser.form.IFormCollaborationView"
    permission="zope.ManageServices"
    />

<editform
    name="index.html"
    schema=
    "zope.app.interfaces.services.registration.INamedComponentRegistration."
    menu="zmi_views"
    label="Edit Registration"
    permission="zope.ManageServices"
    fields="name componentPath permission status"
    />

<page
    name="index.html" 
    for="zope.app.interfaces.services.registration.INameComponentRegistry"
    class=".NameComponentRegistryView"
    permission="zope.ManageServices"
    attribute="index" 
    />

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

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

<!-- RegistrationManager -->

<page
   name="index.html" 
   for="zope.app.interfaces.services.registration.IRegistrationManager"
   menu="zmi_views" title="Registration"
   permission="zope.ManageServices"
   class=".EditRegistration"
   template="editregistration.pt" 
   />

<!-- For now, we'll allow CMs to be added, but we won't include them
     in the add_component menu. -->
<view
   for="zope.app.interfaces.services.registration.IRegistrationManager"
   name="+"
   menu="zmi_actions" title="Add"
   permission="zope.ManageServices"
   class=".RegistrationAdding">
  <page name="index.html"  attribute="index"  />
  <page name="action.html" attribute="action" />
</view>

<!-- Error views -->

<page
    for="
    zope.app.interfaces.services.registration.INoRegistrationManagerError"
    name="index.html"
    permission="zope.Public"
    template="../../exception/user.pt"
    class="zope.app.browser.exception.user.UserErrorView"
    />
<page
    for="zope.app.interfaces.services.registration.INoLocalServiceError"
    name="index.html"
    permission="zope.Public"
    template="../../exception/user.pt"
    class="zope.app.browser.exception.user.UserErrorView"
    />

</zopeConfigure>


=== Added File Zope3/src/zope/app/browser/services/registration/editregistration.pt ===
<html metal:use-macro="views/standard_macros/page">
  <head>
    <title>View Registration Manager</title>
  </head>

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

    <h2>Registration 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/registration/namecomponentregistry.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">Registered fruits in this fruits manager.</h2>

  <div tal:condition="not:registries">
       <p metal:define-slot="empty_text">No fruits have been registered</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/registration/nameregistry.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">Registered fruits in this fruits manager.</h2>

  <div tal:condition="not:registries">
       <p metal:define-slot="empty_text">No fruits have been registered</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 register 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 registration that registers 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/registration/registered.pt ===
<html metal:use-macro="context/@@standard_macros/page">
  <body>
    <div metal:fill-slot="body">

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

      <ul>

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

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

	</li>
      </ul>

      <p><a href="addRegistration.html">Add a registration for this object</a>

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