[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/onlinehelp/ Online Help Restructuring - Part 2

Eckart Hertzler eckart at hertzler.de
Tue Jun 1 06:53:56 EDT 2004


Log message for revision 25144:

Online Help Restructuring - Part 2

 - Ripped out the internal registry of the OnlineHelp.
   OnlineHelpTopic instances are now registered as Utilities

 - Registration of Help Topics does not depend on
   the registration orde anymore.
   If an topic is registered with a non existant parent
   it is only registered as a Utility.
   If the missing parent is registered later, the topic
   will be available through the hierarchy as well.





-=-
Modified: Zope3/trunk/src/zope/app/onlinehelp/DEPENDENCIES.cfg
===================================================================
--- Zope3/trunk/src/zope/app/onlinehelp/DEPENDENCIES.cfg	2004-06-01 08:24:26 UTC (rev 25143)
+++ Zope3/trunk/src/zope/app/onlinehelp/DEPENDENCIES.cfg	2004-06-01 10:53:56 UTC (rev 25144)
@@ -2,8 +2,8 @@
 zope.app
 zope.app.file
 zope.app.renderer
+zope.app.i18n
 zope.configuration
-zope.i18n
 zope.interface
 zope.proxy
 zope.schema

Modified: Zope3/trunk/src/zope/app/onlinehelp/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/onlinehelp/__init__.py	2004-06-01 08:24:26 UTC (rev 25143)
+++ Zope3/trunk/src/zope/app/onlinehelp/__init__.py	2004-06-01 10:53:56 UTC (rev 25144)
@@ -20,12 +20,18 @@
 import os
 
 import zope
+from zope.interface import providedBy
 from zope.app import zapi
+
+from interfaces import IOnlineHelpTopic
 from onlinehelp import OnlineHelp
-from onlinehelptopic import OnlineHelpTopic
-from zope.app.onlinehelp.interfaces import IOnlineHelp    
 
+# Global Online Help Instance
+path = os.path.join(os.path.dirname(zope.app.__file__),
+                    'onlinehelp', 'help','welcome.stx')
+help = OnlineHelp('Online Help', path)
 
+
 class helpNamespace:
     """ help namespace handler """
 
@@ -33,14 +39,62 @@
         self.context = context
 
     def traverse(self, name, ignored):
-        """Used to traverse to an online help topic."""
-        onlinehelp = zapi.getUtility(IOnlineHelp,
-                                          'OnlineHelp', self.context)
-        onlinehelp.context = self.context
-        return onlinehelp
+        """Used to traverse to an online help topic.
+        Returns the global OnlineHelp instance with the traversal
+        context.
+        """
+        help.context = self.context
+        return help
 
-# Global Online Help
-path = os.path.join(os.path.dirname(zope.app.__file__),
-                    'onlinehelp', 'help','welcome.stx')
+def getTopicFor(obj, view=None):
+    """Determine topic for an object and optionally a view.
+    Iterate through all directly provided Interfaces and
+    see if for the interface (and view) exists a Help Topic.
 
-help = OnlineHelp('Online Help', path)
+    Returns the first match.
+
+    Prepare the tests:
+    >>> import os
+    >>> from tests.test_onlinehelp import testdir
+    >>> from tests.test_onlinehelp import I1, Dummy1, Dummy2
+    >>> path = os.path.join(testdir(), 'help.txt')
+
+    Register a help topic for the interface 'I1' and the view 'view.html'
+    >>> onlinehelp = OnlineHelp('Help', path)
+    >>> path = os.path.join(testdir(), 'help2.txt')
+    >>> onlinehelp.registerHelpTopic('', 'help2', 'Help 2',
+    ...     path, I1, 'view.html')
+
+    The query should return it ('Dummy1' implements 'I1):
+    >>> getTopicFor(Dummy1(),'view.html').title
+    'Help 2'
+
+    A query without view should not return it
+    >>> getTopicFor(Dummy1()) is None
+    True
+
+    Do the registration again, but without a view:
+    >>> onlinehelp = OnlineHelp('Help', path)
+    >>> onlinehelp.registerHelpTopic('', 'help2', 'Help 2',
+    ...     path, I1, None)
+    >>> getTopicFor(Dummy1()).title
+    'Help 2'
+
+    Query with view should not match
+    >>> getTopicFor(Dummy1(), 'view.html') is None
+    True
+
+    Query with an object, that does not provide 'I1' should
+    also return None
+    >>> getTopicFor(Dummy2()) is None
+    True
+
+    """
+    topic = None
+    for interface in providedBy(obj):
+        for t in zapi.getUtilitiesFor(IOnlineHelpTopic):
+            if t[1].interface==interface and t[1].view==view:
+                topic = t[1]
+                break
+
+    return topic

Modified: Zope3/trunk/src/zope/app/onlinehelp/browser/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/onlinehelp/browser/__init__.py	2004-06-01 08:24:26 UTC (rev 25143)
+++ Zope3/trunk/src/zope/app/onlinehelp/browser/__init__.py	2004-06-01 10:53:56 UTC (rev 25144)
@@ -22,6 +22,7 @@
 from zope.app.publisher.interfaces.browser import IBrowserView
 
 from zope.app.onlinehelp.interfaces import IOnlineHelpTopic, IOnlineHelp
+from zope.app.onlinehelp import getTopicFor
 
 class TopicTreeView(object):
 
@@ -101,11 +102,11 @@
 
         If the context is a view, try to find
         a matching help topic for the view and its context.
-        If not help topic is found, try got get a help topic for
-        and interface only.
+        If no help topic is found, try to get a help topic for
+        the context only.
 
         If the context is not a view, try to retrieve a help topic
-        for an interface only.
+        based on the context.
 
         If nothing is found, return the onlinehelp root topic
 
@@ -115,20 +116,23 @@
 
         onlinehelp = removeAllProxies(self.context)
         help_context = onlinehelp.context
-        self.topic = self.context
+        self.topic = None
         if IBrowserView.providedBy(help_context):
             # called from a view
-            self.topic = onlinehelp.getTopicForObjectAndView(
+            self.topic = getTopicFor(
                 zapi.getParent(help_context),
                 zapi.getName(help_context)
                 )
-            if self.topic == self.context:
-                # nothing found for view try iface only
-                self.topic = onlinehelp.getTopicForObjectAndView(
+            if self.topic is None:
+                # nothing found for view try context only
+                self.topic = getTopicFor(
                     zapi.getParent(help_context)
                     )
         else:
             # called without view
-            self.topic = onlinehelp.getTopicForObjectAndView(help_context)
+            self.topic = getTopicFor(help_context)
 
+        if self.topic is None:
+            self.topic = onlinehelp
+
         return self.topic

Modified: Zope3/trunk/src/zope/app/onlinehelp/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/onlinehelp/configure.zcml	2004-06-01 08:24:26 UTC (rev 25143)
+++ Zope3/trunk/src/zope/app/onlinehelp/configure.zcml	2004-06-01 10:53:56 UTC (rev 25144)
@@ -4,10 +4,10 @@
    i18n_domain="zope"
    >
 
-  <content class="zope.app.onlinehelp.OnlineHelpTopic">
+  <content class=".onlinehelptopic.OnlineHelpTopic">
     <require
         permission="zope.View"
-        interface="zope.app.onlinehelp.interfaces.IOnlineHelpTopic"
+        interface=".interfaces.IOnlineHelpTopic"
         />
   </content>
 
@@ -18,13 +18,14 @@
         />
   </content>
 
-  <!-- Setup OnlineHelp as a Utility -->
+  <!-- Setup OnlineHelp Root as a Utility -->
   <utility
       provides=".interfaces.IOnlineHelp"
       permission="zope.Public"
       component="zope.app.onlinehelp.help"
       name="OnlineHelp" />
 
+  <!-- Help Namespace Configuration -->
   <view
       name="help" 
       type="*"
@@ -41,7 +42,7 @@
       />
 
   <!-- Register initial Help Topics -->
-  <help:register 
+  <help:register
       id="ui"
       title="Zope UI Help"
       doc_path="./help/ui.stx"

Modified: Zope3/trunk/src/zope/app/onlinehelp/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/app/onlinehelp/interfaces.py	2004-06-01 08:24:26 UTC (rev 25143)
+++ Zope3/trunk/src/zope/app/onlinehelp/interfaces.py	2004-06-01 10:53:56 UTC (rev 25144)
@@ -18,27 +18,42 @@
 $Id$
 """
 from zope.schema import TextLine, SourceText, Choice
+from zope.configuration.fields import GlobalObject
 from zope.app.container.interfaces import IContainer
-from zope.i18n import MessageIDFactory
 from zope.app.file.interfaces import IFile, IFileContent
+from zope.app.i18n import ZopeMessageIDFactory as _ 
 
-_ = MessageIDFactory('messageboard')
-
 class IOnlineHelpTopic(IContainer):
-    """A Topic is one help page that you could view. Topics will be able to
+    """A Topic is a single help page that you can view. Topics are able to
     contain other Topics and so on.
 
     You can also associate a Topic with a particular view.
     
-    The Topic's content can be in the following three forms:
-    Plain Text, HTML and Structured Text (STX). The Content is usually
-    stored in a file and not the Topic itself. The file is only read
-    when required.
+    The Topic's content can be in the following four formats:
+     - Plain Text,
+     - HTML,
+     - Structured Text (STX) and
+     - Restructured Text (ReST).
+
+    The Content is stored in a file and not the Topic itself.
+    The file is only read when required.
     
     Note that all the Sub-Topic management is done by the IContainer
     interface. 
     """
 
+    id = TextLine(
+        title = _(u"Id"),
+        description = _(u"The Id of this Help Topic"),
+        default = u"",
+        required = True)
+
+    parentPath = TextLine(
+        title = _(u"Parent Path"),
+        description = _(u"The Path to the Parent of this Help Topic"),
+        default = u"",
+        required = False)
+
     title = TextLine(
         title = _(u"Help Topic Title"),
         description = _(u"The Title of a Help Topic"),
@@ -65,28 +80,39 @@
         required = True,
         vocabulary = "SourceTypes")
 
+    interface = GlobalObject(
+        title=_(u"Object Interface"),
+        description=_(u"Interface for which this Help Topic is registered."),
+        default=None,
+        required=False)
+
+    view = TextLine(
+        title = _(u"View Name"),
+        description = _(u"The View Name for which this Help Topic"
+                        " is registered"),
+        default = _(u""),
+        required = True)
+
     def addResources(resources):
         """ Add resources to this Help Topic.
         The resources must be located in the same directory
         as the Help Topic itself."""
 
+    def getTopicPath():
+        """ return the presumed path to the topic, even the topic is not
+        traversable from the onlinehelp. """
+
 class IOnlineHelp(IOnlineHelpTopic):
-    """This service manages all the HelpTopics."""
+    """The root of an onlinehelp hierarchy.
+    Manages the registration of new topics.
+    """
 
-    def getTopicsForInterfaceAndView(interface, view=None):
-        """Returns a list of Topics that were registered to be
-        applicable to a particular view of an interface."""
-
-    def getTopicForObjectAndView(obj, view=None):
-        """Returns the first matching help topic for
-        the interfaces provided by obj."""
-
     def registerHelpTopic(parent_path, id, title, doc_path,  
-                          interface=None, view=None):
+                          interface=None, view=None, resources=None):
         """This method registers a topic at the correct place.
 
            parent_path -- Location of this topic's parent in the OnlineHelp
-           tree.
+           tree. Need not to exist at time of creation. 
 
            id -- Specifies the id of the topic 
 
@@ -103,6 +129,10 @@
            view -- This attribute specifies the name of the view for which
            this topic is registered. Note that this attribute is also
            optional.
+
+           resources -- Specifies a list of resources for the topic,
+           for example images that are included by the rendered topic content.
+           Optional.
         """
 
 class IOnlineHelpResource(IFile, IFileContent):

Modified: Zope3/trunk/src/zope/app/onlinehelp/onlinehelp.py
===================================================================
--- Zope3/trunk/src/zope/app/onlinehelp/onlinehelp.py	2004-06-01 08:24:26 UTC (rev 25143)
+++ Zope3/trunk/src/zope/app/onlinehelp/onlinehelp.py	2004-06-01 10:53:56 UTC (rev 25144)
@@ -18,12 +18,12 @@
 
 $Id$
 """
-from zope.interface import implements, providedBy
-
+from zope.interface import implements
+from zope.component.servicenames import Utilities
 from zope.app import zapi
 from zope.app.traversing.interfaces import IContainmentRoot
 
-from zope.app.onlinehelp.interfaces import IOnlineHelp
+from zope.app.onlinehelp.interfaces import IOnlineHelp, IOnlineHelpTopic
 from zope.app.onlinehelp.onlinehelptopic import OnlineHelpTopic
 
 class OnlineHelp(OnlineHelpTopic):
@@ -37,7 +37,7 @@
     
     >>> onlinehelp = OnlineHelp('Help', path)
 
-    First do the inteface verifing tests.
+    First do the interface verifying tests.
     
     >>> from zope.interface.verify import verifyObject
     >>> from zope.app.traversing.interfaces import IContainmentRoot
@@ -56,68 +56,80 @@
     >>> onlinehelp['help2'].title
     'Help 2'
 
-    >>> onlinehelp._registry[(I1, 'view.html')][0].title
+    Additionally it should appear as a utility
+    >>> from zope.app import zapi
+    >>> topic = zapi.getUtility(IOnlineHelpTopic,'help2')
+    >>> topic.title
     'Help 2'
 
-    The help topic must be found if the onlinehelp is queried
-    with interface and view name.
-    
-    >>> onlinehelp.getTopicsForInterfaceAndView(I1, 'view.html')[0].title
-    'Help 2'
+    add another topic without parent
+    >>> onlinehelp.registerHelpTopic('missing', 'help3', 'Help 3',
+    ...     path, I1, 'view.html')
 
-    If queried with an instance the help topic must still be found
-    >>> onlinehelp.getTopicForObjectAndView(Dummy1(), 'view.html').title
-    'Help 2'
+    The new topic should not be a child of the onlinehelp instance
+    >>> 'help3' in onlinehelp.keys()
+    False
 
-    To register help for an interface only simple skip the view parameter
-    while registering.
-    >>> onlinehelp.registerHelpTopic('', 'help3', 'Help for Interface',
-    ...     path, I1)
-    >>> onlinehelp.getTopicForObjectAndView(Dummy1()).title
-    'Help for Interface'
+    But it is available as a utility
+    >>> topic = zapi.getUtility(IOnlineHelpTopic,'missing/help3')
+    >>> topic.title
+    'Help 3'
 
-    
+    now register the missing parent
+    >>> onlinehelp.registerHelpTopic('', 'missing', 'Missing',
+    ...     path, I1, 'view.html')
+
+    This is a child on the onlinehelp
+    >>> 'missing' in onlinehelp.keys()
+    True
+
+    >>> missing = onlinehelp['missing']
+
+    This topic should now have 'help3' as a child
+    >>> 'help3' in missing.keys()
+    True
+
     """
     implements(IOnlineHelp, IContainmentRoot)
 
     def __init__(self, title, path):
-        self._registry = {}
-        super(OnlineHelp, self).__init__(title, path)
+        super(OnlineHelp, self).__init__('',title, path, None)
 
-    def getTopicsForInterfaceAndView(self, interface, view=None):
-        "See zope.app.onlinehelp.interfaces.IOnlineHelp"
-        return self._registry.get((interface, view), [])
-
-    def getTopicForObjectAndView(self, obj, view=None):
-        "See zope.app.Onlinehelp.interfaces.IOnlineHelp"
-        topic = self
-        for iface in providedBy(obj):
-            topics = self.getTopicsForInterfaceAndView(
-                iface,
-                view
-                )
-            if len(topics)>0:
-                topic = topics[0]
-                break
-        return topic
-
     def registerHelpTopic(self, parent_path, id, title,
                           doc_path, interface=None, view=None,
                           resources=None):
-        "See Zope.App.OnlineHelp.interfaces.IOnlineHelp"
-        parent = zapi.traverse(self, parent_path)
-        # Create and add topic
-        parent[id] = OnlineHelpTopic(title, doc_path)
-        topic = parent[id]
+        "See zope.app.onlineHelp.interfaces.IOnlineHelp"
+        # Create topic
+        topic = OnlineHelpTopic(id,
+                                title,
+                                doc_path,
+                                parent_path,
+                                interface,
+                                view)
 
         # add resources to topic
         if resources is not None:
             topic.addResources(resources)
 
-        # Add topic to registry
-        if interface is not None:
-            if not self._registry.has_key((interface, view)):
-                self._registry[(interface, view)] = []
-            self._registry[(interface, view)].append(topic)
+        # add topic to onlinehelp hierarchy
+        parent = None
+        try:
+            parent = zapi.traverse(self, parent_path)
+            parent[id] = topic
+        except KeyError:
+            pass
 
+        for t in zapi.getUtilitiesFor(IOnlineHelpTopic):
+            if parent is None:
+                if t[1].getTopicPath() == parent_path:
+                    t[1][id] = topic
+            if topic.getTopicPath() == t[1].parentPath:
+                topic[t[1].id] = t[1]
 
+        # Add topic to utilities registry
+        zapi.getService(Utilities
+                        ).provideUtility(IOnlineHelpTopic,
+                                         topic,
+                                         topic.getTopicPath())
+
+

Modified: Zope3/trunk/src/zope/app/onlinehelp/onlinehelptopic.py
===================================================================
--- Zope3/trunk/src/zope/app/onlinehelp/onlinehelptopic.py	2004-06-01 08:24:26 UTC (rev 25143)
+++ Zope3/trunk/src/zope/app/onlinehelp/onlinehelptopic.py	2004-06-01 10:53:56 UTC (rev 25144)
@@ -76,13 +76,20 @@
 
     Create a Help Topic from a file
     
-    >>> topic = OnlineHelpTopic('Help',path)
+    >>> topic = OnlineHelpTopic('help','Help',path,'')
 
     Test the title
     
     >>> topic.title
     'Help'
 
+    Test the topic path
+    >>> topic.getTopicPath()
+    'help'
+    >>> topic.parentPath = 'parent'
+    >>> topic.getTopicPath()
+    'parent/help'
+
     The type should be set to plaintext, since
     the file extension is 'txt'
     
@@ -95,7 +102,7 @@
     'This is a help!'
 
     >>> path = os.path.join(testdir(), 'help.stx')
-    >>> topic = OnlineHelpTopic('Help',path)
+    >>> topic = OnlineHelpTopic('help','Help',path,'')
 
     The type should now be structured text
     >>> topic.type
@@ -103,14 +110,14 @@
 
     HTML files are treated as structured text files
     >>> path = os.path.join(testdir(), 'help.html')
-    >>> topic = OnlineHelpTopic('Help',path)
+    >>> topic = OnlineHelpTopic('help','Help',path,'')
 
     The type should still be structured text
     >>> topic.type
     'zope.source.stx'
 
     >>> path = os.path.join(testdir(), 'help.rst')
-    >>> topic = OnlineHelpTopic('Help',path)
+    >>> topic = OnlineHelpTopic('help','Help',path,'')
 
     The type should now be restructured text
     >>> topic.type
@@ -127,10 +134,14 @@
     """
     implements(IOnlineHelpTopic)
 
-    def __init__(self, title, path):
+    def __init__(self, id, title, path, parentPath, interface=None, view=None):
         """Initialize object."""
+        self.id = id
+        self.parentPath = parentPath
         self.title = title
         self.path = path
+        self.interface = interface
+        self.view = view
 
         filename = os.path.basename(path.lower())
         file_ext = 'txt'
@@ -153,18 +164,25 @@
 
         super(OnlineHelpTopic, self).__init__()
 
+    id = u""
+
+    parentPath = u""
+
     title = u""
 
     path = u""
 
     type = None
 
+    interface = None
+
+    view = None
+
     def _getSource(self):
         return open(os.path.normpath(self.path)).read()
 
     source = property(_getSource)
 
-
     def addResources(self, resources):
         """ see IOnlineHelpTopic """
         dirname = os.path.dirname(self.path)
@@ -172,3 +190,11 @@
             resource_path=dirname+'/'+resource
             if os.path.exists(resource_path):
                 self[resource] = OnlineHelpResource(resource_path)
+
+    def getTopicPath(self):
+        """ see IOnlineHelpTopic """
+        if self.parentPath != '':
+            return self.parentPath+'/'+self.id
+        else:
+            return self.id
+                

Modified: Zope3/trunk/src/zope/app/onlinehelp/tests/test_helpdirectives.py
===================================================================
--- Zope3/trunk/src/zope/app/onlinehelp/tests/test_helpdirectives.py	2004-06-01 08:24:26 UTC (rev 25143)
+++ Zope3/trunk/src/zope/app/onlinehelp/tests/test_helpdirectives.py	2004-06-01 10:53:56 UTC (rev 25144)
@@ -46,7 +46,6 @@
         self.assertEqual(help.keys(), [])
         self.context = xmlconfig.file("help.zcml", tests)
         self.assertEqual(help.keys(), ['help1'])
-        self.assertEqual(help._registry[(I1, 'view.html')][0].title, 'Help')
         topic = help['help1']
         self.assert_('test1.png' in topic.keys())
 

Modified: Zope3/trunk/src/zope/app/onlinehelp/tests/test_onlinehelp.py
===================================================================
--- Zope3/trunk/src/zope/app/onlinehelp/tests/test_onlinehelp.py	2004-06-01 08:24:26 UTC (rev 25143)
+++ Zope3/trunk/src/zope/app/onlinehelp/tests/test_onlinehelp.py	2004-06-01 10:53:56 UTC (rev 25144)
@@ -33,6 +33,9 @@
 class Dummy1:
     implements(I1)
 
+class Dummy2:
+    pass
+
 def testdir():
     import zope.app.onlinehelp.tests
     return os.path.dirname(zope.app.onlinehelp.tests.__file__)
@@ -44,12 +47,12 @@
     ztapi.provideAdapter(None, IPhysicallyLocatable,
                          LocationPhysicallyLocatable)
 
-
 def test_suite():
       return unittest.TestSuite((
+          DocTestSuite('zope.app.onlinehelp', setUp=setUp),
           DocTestSuite('zope.app.onlinehelp.onlinehelptopic', setUp=setUp),
           DocTestSuite('zope.app.onlinehelp.onlinehelp', setUp=setUp),
           ))
-  
+
 if __name__ == '__main__':
       unittest.main(defaultTest='test_suite')




More information about the Zope3-Checkins mailing list