[Zope3-checkins] CVS: Zope3/src/zope/app/browser/services - add_svc_config.pt:1.2 useconfiguration.pt:1.2 useconfiguration.py:1.2 configure.zcml:1.21 service.py:1.7 add_service_1.pt:NONE add_service_2.pt:NONE

Guido van Rossum guido@python.org
Mon, 3 Mar 2003 18:16:36 -0500


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

Modified Files:
	configure.zcml service.py 
Added Files:
	add_svc_config.pt useconfiguration.pt useconfiguration.py 
Removed Files:
	add_service_1.pt add_service_2.pt 
Log Message:
Merge from use-config-branch.  (A joint production by Jim, Tim and Guido.)

- Refactor the service creation and configuration code, making the UI
  for creating and configuring services much more pleasant.

- Add a new marker interface, IUseConfigurable, which is used to say
  that an object records dependencies between it and its
  configurations.  (This applies to other configurable objects besides
  services.)  Another marker interface, IAttributeUseConfigurable,
  says that these dependencies are stored as annotations.  And finally
  IUseConfiguration defines the actual interface for discussing these
  dependencies; implementing IUseConfigurable is a promise that such
  an adapter exists (and implementing IAttributeUseConfigurable is one
  way of making this promise come true :-).

- Add a new view tab for services, called "Configurations", which
  displays links to its configurations with summary information.  (Try
  it for the Events service, which has two configurations by default.)

- Add a new interface, ILocalService, which all local services must
  implement.  Also add ISimpleService, which extends ILocalService
  with IAttributeUseConfigurable.  All existing local service
  implementations implement this.

- Some miscellaneous cleanup (e.g. made the browser namespace the
  default namespace in zope/app/browser/services/configure.zcml).


=== Zope3/src/zope/app/browser/services/add_svc_config.pt 1.1 => 1.2 ===
--- /dev/null	Mon Mar  3 18:16:36 2003
+++ Zope3/src/zope/app/browser/services/add_svc_config.pt	Mon Mar  3 18:16:04 2003
@@ -0,0 +1,48 @@
+<html metal:use-macro="context/@@standard_macros/page">
+  <body>
+    <div metal:fill-slot="body">
+
+      <form action="add_svc_config.html">
+
+        <p>Configure this object to provide the following service(s):
+
+        <table>
+
+          <thead>
+            <tr>
+              <th>Configure</th>
+              <th>Service name</th>
+              <th>Activate</th>
+            </tr>
+          </thead>
+
+          <tbody>
+	    <tr tal:repeat="item view/listServiceTypes">
+
+	      <td>
+		<input type="checkbox" name="name:list" value="value" checked
+		       tal:attributes="value item/name">
+              </td>
+	      <td tal:content="item/name">Events
+	      </td>
+
+	      <td>
+		<input type="checkbox" name="active:list" value="value"
+		       tal:attributes="value item/name;
+				       checked item/checked">
+	      </td>
+
+	    </tr>
+          </tbody>
+
+	</table>
+
+	<input type="reset" value="Reset form">
+        <input type="submit" value="Submit">
+
+
+      </form>
+
+    </div>
+  </body>
+</html>


=== Zope3/src/zope/app/browser/services/useconfiguration.pt 1.1 => 1.2 ===
--- /dev/null	Mon Mar  3 18:16:36 2003
+++ Zope3/src/zope/app/browser/services/useconfiguration.pt	Mon Mar  3 18:16:04 2003
@@ -0,0 +1,24 @@
+<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>


=== Zope3/src/zope/app/browser/services/useconfiguration.py 1.1 => 1.2 ===
--- /dev/null	Mon Mar  3 18:16:36 2003
+++ Zope3/src/zope/app/browser/services/useconfiguration.py	Mon Mar  3 18:16:04 2003
@@ -0,0 +1,40 @@
+##############################################################################
+# 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.
+##############################################################################
+"""Use-Configuration view
+
+$Id$
+"""
+__metaclass__ = type
+
+from zope.component import getAdapter, getView
+from zope.app.interfaces.services.configuration import IUseConfiguration
+from zope.app.traversing import traverse
+
+class UseConfiguration:
+
+    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


=== Zope3/src/zope/app/browser/services/configure.zcml 1.20 => 1.21 === (930/1030 lines abridged)
--- Zope3/src/zope/app/browser/services/configure.zcml:1.20	Fri Feb 21 09:50:05 2003
+++ Zope3/src/zope/app/browser/services/configure.zcml	Mon Mar  3 18:16:04 2003
@@ -1,33 +1,34 @@
 <zopeConfigure
-   xmlns='http://namespaces.zope.org/zope'
-   xmlns:browser='http://namespaces.zope.org/browser'
+   xmlns='http://namespaces.zope.org/browser'
    >
 
 <!--Error Reporting Service -->
 
-  <browser:pages
+  <pages
     for="zope.app.interfaces.services.error.IErrorReportingService"
     permission="zope.Public"
     class="zope.app.browser.services.error.EditErrorLog">
 
-    <browser:page name="index.html" template="error.pt" />
-    <browser:page name="edit.html" attribute="updateProperties" />
-    <browser:page name="showEntry.html" template="errorentry.pt"/>
-    <browser:page name="showTextTBEntry.html"
+    <page name="index.html" template="error.pt" />
+    <page name="edit.html" attribute="updateProperties" />
+    <page name="showEntry.html" template="errorentry.pt"/>
+    <page name="showTextTBEntry.html"
        template="texttbentry.pt"/>
-    </browser:pages>
+    </pages>
 
-  <browser:menuItem menu="add_component"
+  <menuItem
+     menu="add_service"
      for="zope.app.interfaces.container.IAdding" 
-     action="ErrorReportingService"  title='Error Reporting Service'
-     description='Error Reporting Service for Logging Errors'
+     action="ErrorReportingService"
+     title="Error Reporting Service"
+     description="Error Reporting Service for Logging Errors"
      />
   
-  <browser:icon name="zmi_icon" 
+  <icon name="zmi_icon" 
       for="zope.app.interfaces.services.error.IErrorReportingService" 
       file="error_service.gif" />
 
-  <browser:menuItem
+  <menuItem
       for="zope.app.interfaces.services.error.IErrorReportingService" 
       menu="zmi_views"
       title="Errors"

[-=- -=- -=- 930 lines omitted -=- -=- -=-]

+<page
     name="index.html" 
     menu="zmi_views" title="Control"
     permission="zope.ManageServices" 
@@ -831,18 +846,41 @@
     attribute="index" 
     />
 
-  <browser:menuItem
-      menu="add_component"
+  <menuItem
+      menu="add_service"
       for="zope.app.interfaces.container.IAdding"
       action="ObjectHub"
-      title='ObjectHub'
+      title="ObjectHub Service"
       description="An object hub, for cataloging, unique object ids, and 
                    more: use sparingly" 
       />
 
-  <browser:icon
+  <icon
       name="zmi_icon"
       for="zope.app.interfaces.services.hub.IObjectHub" 
       file="hub.gif" />
+
+
+<!-- "Add Service" menu -->
+
+<menuItem
+    menu="add_component"
+    for="zope.app.interfaces.container.IAdding"
+    action="../AddService"
+    title="Service"
+    description="Takes you to a menu of services to add"
+    permission="zope.ManageServices"
+    />
+
+  <view
+     name="AddService"
+     for="zope.app.interfaces.services.package.IPackage"
+     permission="zope.ManageServices"
+     class="zope.app.browser.services.service.ServiceAdding">
+
+    <page name="index.html"  attribute="index"  />
+    <page name="action.html" attribute="action" />
+
+  </view>
 
 </zopeConfigure>


=== Zope3/src/zope/app/browser/services/service.py 1.6 => 1.7 ===
--- Zope3/src/zope/app/browser/services/service.py:1.6	Fri Feb 21 09:53:34 2003
+++ Zope3/src/zope/app/browser/services/service.py	Mon Mar  3 18:16:04 2003
@@ -16,7 +16,7 @@
 $Id$
 """
 
-from zope.app.browser.container.adding import Adding as ContentAdding
+from zope.app.browser.container.adding import Adding
 from zope.component import getView, getAdapter
 from zope.proxy.context import ContextWrapper, ContextSuper
 from zope.app.interfaces.container import IZopeContainer
@@ -25,30 +25,68 @@
 from zope.app.services.service import ServiceConfiguration
 from zope.app.interfaces.services.configuration import IConfiguration
 from zope.app.form.utility import setUpWidgets, getWidgetsDataForContent
+from zope.app.traversing import traverse, getPhysicalPathString
+from zope.app.interfaces.services.interfaces import ILocalService
+from zope.proxy.context import getWrapperContainer
+from zope.app.interfaces.services.configuration \
+     import Unregistered, Registered, Active
 
 __metaclass__ = type
 
-class ComponentAdding(ContentAdding):
+class ComponentAdding(Adding):
     """Adding component for components
     """
 
     menu_id = "add_component"
 
     def action(self, type_name, id):
+        if type_name == "../AddService":
+            # Special case
+            url = type_name
+            if id:
+                url += "?id=" + id
+            self.request.response.redirect(url)
+            return
+
         if not id:
             # Generate an id from the type name
             id = type_name
             l = id.rfind('.')
             if l >= 0:
                 id = id[l+1:]
-            if id in self.context:
-                i=2
-                while ("%s-%s" % (id, i)) in self.context:
-                    i=i+1
-                id = "%s-%s" % (id, i)
-        return ContextSuper(ComponentAdding, self).action(type_name, id)
+            i = 1
+            while ("%s-%s" % (id, i)) in self.context:
+                i=i+1
+            id = "%s-%s" % (id, i)
+
+        # Call the superclass action() method.
+        # As a side effect, self.added_object is set by add() above.
+        ContextSuper(ComponentAdding, self).action(type_name, id)
+
+
+class ServiceAdding(ComponentAdding):
+    """Adding a service."""
+
+    menu_id = "add_service"
+
+    def add(self, content):
+        # Override so as to save a reference to the added object
+        self.added_object = ContextSuper(ComponentAdding, self).add(content)
+        return self.added_object
+
+    def action(self, type_name, id):
+        # Call the superclass action() method.
+        # As a side effect, self.added_object is set by add() above.
+        ContextSuper(ServiceAdding, self).action(type_name, id)
+
+        if not ILocalService.isImplementedBy(self.added_object):
+            raise TypeError("%s is not a local service" % self.added_object)
+
+        url = getPhysicalPathString(self.added_object)
+        self.request.response.redirect(url + "/addConfiguration.html")
+
 
-class ConfigurationAdding(ContentAdding):
+class ConfigurationAdding(Adding):
     """Adding component for configuration
     """
 
@@ -116,31 +154,38 @@
             r.append({'key': name, 'view': view})
         return r
 
-class AddServiceConfiguration(BrowserView):
 
-    def __init__(self, *args):
-        super(AddServiceConfiguration, self).__init__(*args)
-        setUpWidgets(self, IConfiguration)
-
-    def services(self):
-        service = getServiceManager(self.context.context)
-        definitions = service.getServiceDefinitions()
-        names = [name for (name, interface) in definitions]
-        names.sort()
-        return names
-
-    def components(self):
-        service_type = self.request['service_type']
-        service = getServiceManager(self.context.context)
-        type = service.getInterfaceFor(service_type)
-        paths = [info['path']
-                 for info in service.queryComponent(type=type)
-                 ]
-        paths.sort()
-        return paths
-
-    def action(self, service_type, component_path):
-        sd = ServiceConfiguration(service_type, component_path)
-        sd = self.context.add(sd)
-        getWidgetsDataForContent(self, IConfiguration, sd, strict=False)
-        self.request.response.redirect(self.context.nextURL())
+class AddServiceConfiguration:
+    """A mixin class."""
+
+    def listServiceTypes(self):
+
+        # Collect all defined services interfaces that it implements.
+        sm = getServiceManager(self.context)
+        lst = []
+        for servicename, interface in sm.getServiceDefinitions():
+            if interface.isImplementedBy(self.context):
+                registry = sm.queryConfigurations(servicename)
+                checked = True
+                if registry and registry.active():
+                    checked = False
+                d = {'name': servicename, 'checked': checked}
+                lst.append(d)
+        return lst
+
+    def action(self, name=[], active=[]):
+        path = getPhysicalPathString(self.context)
+        configure = traverse(getWrapperContainer(self.context), 'configure')
+        container = getAdapter(configure, IZopeContainer)
+
+        for nm in name:
+            # XXX Shouldn't hardcode 'configure'
+            sc = ServiceConfiguration(nm, path, self.context)
+            name = container.setObject("", sc)
+            sc = container[name]
+            if nm in active:
+                sc.status = Active
+            else:
+                sc.status = Registered
+
+        self.request.response.redirect("@@useConfiguration.html")

=== Removed File Zope3/src/zope/app/browser/services/add_service_1.pt ===

=== Removed File Zope3/src/zope/app/browser/services/add_service_2.pt ===