[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