[Zope3-checkins] CVS: Zope3/src/zope/app/services - menu.py:1.2 menu.zcml:1.2 configure.zcml:1.54 interface.py:1.15 servicenames.py:1.10 utility.py:1.15 view.py:1.33

Stephan Richter srichter at cosmos.phy.tufts.edu
Fri Aug 15 21:45:17 EDT 2003


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

Modified Files:
	configure.zcml interface.py servicenames.py utility.py view.py 
Added Files:
	menu.py menu.zcml 
Log Message:
Merging dreamcatcher's TTW Schema branch:

1. Fixed Bug in adding that would cause infinite loops when the menu items
   action was not a valif view or factory id.

2. Extended adding to support more complex views. Until now we only 
   supported constructions like "+/AddView=id". Now you are able to say
   "+/AddView/More=id", which means that more information can be carried 
   in the URL. This can be used in many ways, including multi-page adding
   wizards. In my case I needed it to pass in the type of the TTW Schema-
   based Content Component.

3. Added Local Menus. This was a pain in the butt, but I think I got a 
   fairly nice model, where you can create local Menu Services, and Menus
   are simply named utilities. When active they are menus in the menu 
   service. This is very similar to the local interface service and TTW 
   Schema. 

4. Made some modifications to TTW Schema, cleaned up the code and moved
   the browser code and interfaces to the places they belong.

5. Added a Content Component Definition utility component, which takes a
   Schema and creates a content component for it, including permission
   settings and a menu entry. Currently the menu entry is always made to
   a local 'add_content' menu. I will change this and make it actually a
   screen, where the menu and title of the menu item can be chosen by the
   developer. Mmmh, should I add a factory for the definition as well, so
   that the content component is also available via python?

6. Added a Content Component Instance component that represents an 
   instance od a Content Component Definition. You will never directly 
   encounter this component, since it is automatically used by the adding
   code of the Content Component Definition.

7. Cleanups by both dreamcatcher and myself.

That's it. For more details see the branch checkin messages. I now consider
the dreamcatcher-ttwschema-branch closed.


=== Zope3/src/zope/app/services/menu.py 1.1 => 1.2 ===
--- /dev/null	Fri Aug 15 20:45:15 2003
+++ Zope3/src/zope/app/services/menu.py	Fri Aug 15 20:44:08 2003
@@ -0,0 +1,208 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Local Menu Service
+
+$Id$
+"""
+from persistence import Persistent
+from zope.app import zapi
+from zope.app.component.nextservice import getNextService
+from zope.app.container.ordered import OrderedContainer
+from zope.app.interfaces.services.menu import \
+     ILocalBrowserMenu, ILocalBrowserMenuService
+from zope.app.interfaces.publisher.browser import \
+     IBrowserMenuItem, IGlobalBrowserMenuService
+from zope.app.interfaces.services.service import ISimpleService
+from zope.app.publisher.browser.globalbrowsermenuservice import \
+     Menu, BaseBrowserMenuService
+from zope.app.services.servicenames import Utilities, BrowserMenu
+from zope.interface import implements
+from zope.component.exceptions import ComponentLookupError
+from zope.context import ContextMethod
+from zope.interface import providedBy
+from zope.security.proxy import trustedRemoveSecurityProxy
+
+
+class LocalBrowserMenuItem(Persistent):
+    """A persistent browser menu item."""
+
+    implements(IBrowserMenuItem)
+
+    # See zope.app.interfaces.publisher.browser.IBrowserMenuItem
+    interface = None
+
+    # See zope.app.interfaces.publisher.browser.IBrowserMenuItem
+    action = u''
+
+    # See zope.app.interfaces.publisher.browser.IBrowserMenuItem
+    title = u''
+
+    # See zope.app.interfaces.publisher.browser.IBrowserMenuItem
+    description = u''
+
+    # See zope.app.interfaces.publisher.browser.IBrowserMenuItem
+    permission = None
+
+    # See zope.app.interfaces.publisher.browser.IBrowserMenuItem
+    filter_string = u''
+    
+
+class LocalBrowserMenu(OrderedContainer):
+    """A persistent browser menu that can store menu item objects."""
+    
+    implements(ILocalBrowserMenu)
+
+    # See zope.app.interfaces.publisher.browser.IBrowserMenu
+    title = u''
+
+    # See zope.app.interfaces.publisher.browser.IBrowserMenu
+    description = u''
+
+    # See zope.app.interfaces.publisher.browser.IBrowserMenu
+    usage = u''
+
+    # See zope.app.interfaces.publisher.browser.IBrowserMenu
+    inherit = True
+
+    def __init__(self):
+        super(LocalBrowserMenu, self).__init__()
+        self._next = 0
+
+    def getMenuItems(self, object=None):
+        """See zope.app.interfaces.publisher.browser.IBrowserMenu"""
+        result = []
+        interfaces = list(providedBy(object).flattened())
+        for menuitem in self.values():
+            if menuitem.interface in interfaces or object is None:
+                result.append(
+                    (menuitem.action,
+                     menuitem.title,
+                     menuitem.description,
+                     menuitem.filter_string or None,
+                     menuitem.permission))
+
+        return result
+
+    def setObject(self, key, object):
+        """See zope.app.interfaces.container.Container"""
+        self._next += 1
+        key = str(self._next)
+        while key in self:
+            self._next += 1
+            key = str(self._next)
+        super(LocalBrowserMenu, self).setObject(key, object)
+        return key
+
+
+class LocalBrowserMenuService(BaseBrowserMenuService, Persistent):
+    """This implementation strongly depends on the semantics of
+    GlobalBrowserMenuService."""
+    
+    implements(ILocalBrowserMenuService, ISimpleService)
+
+    def __init__(self):
+        super(LocalBrowserMenuService, self).__init__()
+
+
+    def getAllLocalMenus(self):
+        """See zope.app.interfaces.publisher.browser.IBrowserMenuService"""
+        utilities = zapi.getService(self, Utilities)
+        matching = utilities.getRegisteredMatching(ILocalBrowserMenu)
+        return map(lambda m: m[2].active().getComponent(), matching)
+    getAllLocalMenus = ContextMethod(getAllLocalMenus)
+
+
+    def getLocalMenu(self, menu_id):
+        """See zope.app.interfaces.services.menu.ILocalBrowserMenuService"""
+        menu = self.queryLocalMenu(menu_id)
+        if menu is None:
+            raise ComponentLookupError(menu_id)
+        return menu
+    getLocalMenu = ContextMethod(getLocalMenu)
+
+
+    def queryLocalMenu(self, menu_id, default=None):
+        """See zope.app.interfaces.services.menu.ILocalBrowserMenuService"""
+        utilities = zapi.getService(self, Utilities)
+        matching = utilities.getRegisteredMatching(ILocalBrowserMenu, menu_id)
+        if matching and matching[0][2].active():
+            return matching[0][2].active().getComponent()
+        return default
+    queryLocalMenu = ContextMethod(queryLocalMenu)
+
+
+    def getInheritedMenu(self, menu_id, canBeLocal=False):
+        """See zope.app.interfaces.services.menu.ILocalBrowserMenuService"""
+        menu = self.queryInheritedMenu(menu_id, canBeLocal)
+        if menu is None:
+            raise ComponentLookupError(menu_id)
+        return menu
+    getInheritedMenu = ContextMethod(getInheritedMenu)
+
+
+    def queryInheritedMenu(self, menu_id, canBeLocal=False, default=None):
+        """See zope.app.interfaces.services.menu.ILocalBrowserMenuService"""
+        if canBeLocal and self.queryLocalMenu(menu_id):
+            return self.queryLocalMenu(menu_id)
+        # Another service (global) should always be available
+        next = getNextService(self, BrowserMenu)
+
+        # Check whether we deal with a Global Menu Service
+        if IGlobalBrowserMenuService.isImplementedBy(next):
+            return next._registry.get(menu_id, default)
+
+        return next.queryInheritedMenu(menu_id, True, default)        
+    queryInheritedMenu = ContextMethod(queryInheritedMenu)
+
+
+    def getAllMenuItems(self, menu_id, object):
+        """See zope.app.interfaces.publisher.browser.IBrowserMenuService"""
+        result = []
+    
+        # Find the local items, if available 
+        menu = self.queryLocalMenu(menu_id)
+        if menu is not None:
+            result += menu.getMenuItems(object)
+            # We might not want to inherit menu entries from higher up
+            if not menu.inherit:
+                return result
+    
+        # Try to find the next service and get its items. The next service is
+        # also responsible for finding items higher up.
+        next = getNextService(self, BrowserMenu)
+        result += next.getAllMenuItems(menu_id, object)
+
+        return tuple(result)
+    getAllMenuItems = ContextMethod(getAllMenuItems)
+
+
+    def getMenu(self, menu_id, object, request, max=999999):
+        """See zope.app.interfaces.publisher.browser.IBrowserMenuService"""
+        return super(LocalBrowserMenuService,
+                     self).getMenu(menu_id, object, request, max)
+    getMenu = ContextMethod(getMenu)
+
+
+    def getFirstMenuItem(self, menu_id, object, request):
+        """See zope.app.interfaces.publisher.browser.IBrowserMenuService"""
+        return super(LocalBrowserMenuService,
+                     self).getFirstMenuItem(menu_id, object, request)
+    getFirstMenuItem = ContextMethod(getFirstMenuItem)
+
+
+    def getMenuUsage(self, menu_id):
+        """See zope.app.interfaces.publisher.browser.IBrowserMenuService"""
+        return self.getInheritedMenu(menu_id, True).usage
+    getMenuUsage = ContextMethod(getMenuUsage)
+


=== Zope3/src/zope/app/services/menu.zcml 1.1 => 1.2 ===
--- /dev/null	Fri Aug 15 20:45:15 2003
+++ Zope3/src/zope/app/services/menu.zcml	Fri Aug 15 20:44:08 2003
@@ -0,0 +1,68 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope">
+
+<!-- Browser Menu Service -->
+  <content class="zope.app.services.menu.LocalBrowserMenuService">
+    <factory
+        id="zope.app.services.LocalBrowserMenuService"
+        permission="zope.ManageServices"
+        title="Browser Menu Service"
+        description="A Persistent Browser Menu Service" />
+
+    <require
+        permission="zope.ManageServices"
+        interface="zope.app.interfaces.services.registration.IRegistry"
+        attributes="menu menuItem" />
+  </content>
+
+<!-- Browser Menu -->
+  <content class=".menu.LocalBrowserMenu">
+
+    <factory
+      id="zope.app.services.menu.LocalBrowserMenu"
+      permission="zope.ManageServices"
+      title="Browser Menu"
+      description="A Persistent Browser Menu" />
+
+    <allow
+        interface="zope.app.interfaces.container.IReadContainer" />
+
+    <require
+        permission="zope.ManageServices"
+        interface="zope.app.interfaces.container.IWriteContainer" />
+
+    <implements
+      interface="zope.app.interfaces.services.utility.ILocalUtility" />
+
+    <implements
+      interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
+
+    <require
+      permission="zope.ManageServices"
+      interface="zope.app.interfaces.services.menu.ILocalBrowserMenu"
+      set_schema="zope.app.interfaces.services.menu.ILocalBrowserMenu" />
+
+  </content>
+
+<!-- Browser Menu Item -->
+  <content class=".menu.LocalBrowserMenuItem">
+
+    <factory
+      id="utility.LocalBrowserMenuItem"
+      permission="zope.ManageServices"
+      title="Browser Menu Item"
+      description="A Persistent Browser Menu Item" />
+
+    <implements
+      interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
+
+    <require
+      permission="zope.ManageServices"
+      interface="zope.app.interfaces.publisher.browser.IBrowserMenuItem"
+      set_schema="zope.app.interfaces.publisher.browser.IBrowserMenuItem" />
+
+  </content>
+
+
+</configure>
+


=== Zope3/src/zope/app/services/configure.zcml 1.53 => 1.54 ===
--- Zope3/src/zope/app/services/configure.zcml:1.53	Tue Aug 12 18:02:56 2003
+++ Zope3/src/zope/app/services/configure.zcml	Fri Aug 15 20:44:08 2003
@@ -103,6 +103,10 @@
    />
 
 
+<!-- Menu Service -->
+<include file="menu.zcml"/>
+
+
 <!-- Page Templates -->
 
 <content class="zope.app.services.zpt.ZPTTemplate">


=== Zope3/src/zope/app/services/interface.py 1.14 => 1.15 ===
--- Zope3/src/zope/app/services/interface.py:1.14	Sat Aug  9 14:09:32 2003
+++ Zope3/src/zope/app/services/interface.py	Fri Aug 15 20:44:08 2003
@@ -76,10 +76,9 @@
         next = getNextService(self, Interfaces)
         iface = next.queryInterface(id, default)
         if iface is default:
-            utility_service = getService(self, Utilities)
-            utility = utility_service.queryUtility(IInterface, name=id)
-            if utility is not None:
-                return utility
+            utilities = self._queryUtilityInterfaces(search_string=id)
+            if utilities:
+                return utilities[0][1]
             return default
         return iface
 
@@ -112,12 +111,11 @@
         for item in next.items(search_string, base):
             items[item] = None
         for item in self._queryUtilityInterfaces(base, search_string):
-            items[item] = item
+            if not items.has_key(item):
+                items[item] = None
         return items.keys()
 
     def _queryUtilityInterfaces(self, interface=None, search_string=None):
-        if interface is None:
-            interface = IInterface
         utilities = getService(self, Utilities)
         matching = utilities.getUtilitiesFor(interface)
         matching = [m for m in matching


=== Zope3/src/zope/app/services/servicenames.py 1.9 => 1.10 ===
--- Zope3/src/zope/app/services/servicenames.py:1.9	Tue Jul  8 15:57:56 2003
+++ Zope3/src/zope/app/services/servicenames.py	Fri Aug 15 20:44:08 2003
@@ -19,15 +19,16 @@
 
 from zope.component.servicenames import *
 
-HubIds = 'HubIds'
+Authentication = 'Authentication'
+BrowserMenu = 'BrowserMenu'
+DAVSchema = 'DAVSchema'
 EventPublication = 'EventPublication'
 EventSubscription = 'Subscription'
 ErrorLogging = 'ErrorLogging'
-Roles = 'Roles'
+HubIds = 'HubIds'
 Permissions = 'Permissions'
-Authentication = 'Authentication'
-Workflows = 'Workflows'
-Translation = 'Translation'
-DAVSchema = 'DAVSchema'
 PrincipalAnnotation = 'PrincipalAnnotation'
+Roles = 'Roles'
 SQLDatabaseConnections = 'SQLDatabaseConnections'
+Translation = 'Translation'
+Workflows = 'Workflows'


=== Zope3/src/zope/app/services/utility.py 1.14 => 1.15 ===
--- Zope3/src/zope/app/services/utility.py:1.14	Thu Aug  7 11:29:48 2003
+++ Zope3/src/zope/app/services/utility.py	Fri Aug 15 20:44:08 2003
@@ -31,6 +31,7 @@
 from zope.interface.implementor import ImplementorRegistry
 from zope.context import ContextMethod
 from zope.app.context import ContextWrapper
+from zope.proxy import removeAllProxies
 
 class LocalUtilityService(Persistent):
 
@@ -114,10 +115,11 @@
             for iface, cr in self._utilities[name].getRegisteredMatching():
                 if not cr:
                     continue
-                if interface and not iface is interface:
-                    continue
                 cr = ContextWrapper(cr, self)
                 utility = cr.active().getComponent()
+                if interface and not iface.extends(interface, 0) and \
+                       removeAllProxies(utility) is not interface:
+                    continue
                 utilities[(name, utility)] = None
 
         next = getNextService(self, "Utilities")
@@ -126,6 +128,7 @@
             if not utilities.has_key(utility):
                 utilities[utility] = None
         return utilities.keys()
+    
     getUtilitiesFor = ContextMethod(getUtilitiesFor)
 
 class UtilityRegistration(ComponentRegistration):
@@ -147,7 +150,7 @@
 
     def usageSummary(self):
         # Override IRegistration.usageSummary()
-        s = "%s utility" % self.interface.__name__
+        s = "%s utility" % self.interface.getName()
         if self.name:
             s += " named %s" % self.name
         return s


=== Zope3/src/zope/app/services/view.py 1.32 => 1.33 ===
--- Zope3/src/zope/app/services/view.py:1.32	Fri Aug  8 16:47:47 2003
+++ Zope3/src/zope/app/services/view.py	Fri Aug 15 20:44:08 2003
@@ -249,14 +249,14 @@
         if self.forInterface is None:
             ifname = _("(Anything)")
         else:
-            ifname = self.forInterface.__name__
-        summary = _("${view_name} ${ptype} View for {iface_name}")
+            ifname = self.forInterface.getName()
+        summary = _("${view_name} ${ptype} View for ${iface_name}")
         if self.layer and self.layer != "default":
             summary = _(
-                "${view_name} ${ptype} View for {iface_name} in layer ${layer}"
+                "${view_name} ${ptype} View for ${iface_name} in layer ${layer}"
                 )
         summary.mapping = {'view_name':  self.viewName,
-                           'ptype':      self.ptype.__name__,
+                           'ptype':      self.ptype.getName(),
                            'iface_name': ifname,
                            'layer':      self.layer}
         return summary
@@ -294,13 +294,13 @@
         if self.forInterface is None:
             ifname = _("(Anything)")
         else:
-            ifname = self.forInterface.__name__
+            ifname = self.forInterface.getName()
 
-        pname = self.presentationType.__name__
+        pname = self.presentationType.getName()
         summary = _("${view_name} for ${pname} {what} {iface_name}")
         if self.layer and self.layer != "default":
             summary = _(
-                "${view_name} for ${pname} {what} {iface_name} in layer ${layer}"
+                "${view_name} for ${pname} ${what} ${iface_name} in layer ${layer}"
                 )
         summary.mapping = {'view_name':  self.viewName,
                            'pname':      pname,




More information about the Zope3-Checkins mailing list