[Checkins] SVN: Sandbox/ulif/grok-adminui/ Merged admin branch against trunk.

Christian Theune ct at gocept.com
Thu Jul 12 10:07:50 EDT 2007


Log message for revision 77742:
  Merged admin branch against trunk.
  

Changed:
  A   Sandbox/ulif/grok-adminui/doc/groktut/building_forms_with_formlib/
  A   Sandbox/ulif/grok-adminui/doc/macros.txt
  U   Sandbox/ulif/grok-adminui/doc/tutorial.txt
  U   Sandbox/ulif/grok-adminui/src/grok/admin/README.txt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/docgrok.py
  A   Sandbox/ulif/grok-adminui/src/grok/admin/docgrok.txt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/static/
  U   Sandbox/ulif/grok-adminui/src/grok/admin/view.py
  A   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/appsindex.pt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokclassview.pt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokgrokapplicationview.pt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokinterfaceview.pt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokmoduleview.pt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokpackageview.pt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgroktextfileview.pt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokview.pt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/gaiaview.pt
  U   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/index.pt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/macros.pt
  A   Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/z3index.pt
  U   Sandbox/ulif/grok-adminui/src/grok/ftests/admin/admin.py

-=-
Copied: Sandbox/ulif/grok-adminui/doc/groktut/building_forms_with_formlib (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/doc/groktut/building_forms_with_formlib)

Copied: Sandbox/ulif/grok-adminui/doc/macros.txt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/doc/macros.txt)
===================================================================
--- Sandbox/ulif/grok-adminui/doc/macros.txt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/doc/macros.txt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,247 @@
+============================
+Mini-Howto: Macros with Grok
+============================
+
+Intended Audience:
+
+  * Python Developers
+
+  * Zope 2 Developers
+
+  * Zope 3 Developers
+
+
+
+Introduction
+------------
+
+Macros are a way to define a chunk of presentation in one template,
+and share it in others. Changes to the macro are immediately reflected
+in all of the places, that share it.
+
+Such, a developer can easily write some sort of 'page-skeleton' (the
+macro), which can be reused in other pages to take care, for instance,
+for a certain and consistent look-and-feel of a whole site with less
+maintenance.
+
+Technically, macros are made available by ``METAL``, a Macro Expansion
+for TAL, which ships with nearly every Zope installation. They can be
+used in Zope Page Templates. See the `TAL`_ and `METAL`_ pages for
+details.
+
+.. _`TAL`: http://wiki.zope.org/ZPT/TAL
+
+.. _`METAL`: http://wiki.zope.org/ZPT/METAL
+
+
+
+Defining a simple macro
+-----------------------
+
+In Grok macros are defined in usual views, where the associated page
+templates contain `metal`-statements to define the desired
+macros. Macros generally are attributes of the page template wherein they
+are defined, but to get them rendered, we usually use views.
+
+We define a view ``MyMacros`` the usual way in ``app.py``::
+
+   import grok
+
+   class Sample(grok.Application, grok.Container):
+       pass
+
+   class Index(grok.View):
+       pass # see app_templates/index.pt
+
+   class MyMacros(grok.View):
+       """The macro holder"""
+       grok.context(Sample) # The default model this view is bound to.
+
+In the associated page template ``app_templates/mymacros.pt`` we
+define the macros we like to have available. You define macros with
+the ``METAL`` attribute::
+
+    metal:define-macro="<macro-name>"
+
+and the slots therein with::
+
+    metal:define-slots=<slot-name> 
+
+Let's define a very plain page macro::
+
+   <html metal:define-macro="mypage">
+     <head></head>
+     <body>
+       The content:
+       <div metal:define-slot="mycontent">
+         Put your content here...
+       </div>
+     </body>
+   </html>
+
+Here we defined a single macro ``mypage`` with only one slot
+``mycontent``. 
+
+If we restart our Zope instance (don't forget to put some ``index.pt``
+into ``app_templates/``) and have created our application as ``test``,
+we now can go to the following URL::
+
+    http://localhost:8080/test/mymacros
+
+and see the output::
+
+    The content:
+    Put your content here...
+
+Allright.
+
+
+Referencing a simple macro
+--------------------------
+
+In ``index.pt`` we now want to *use* the macro defined in
+``mymacros.pt``. Using a macro means to let it render a part of
+another page template, especially, filling the slots defined in
+``mymacros.pt`` with content defined in ``index.pt``. You call macros
+with the ``METAL`` attribute::
+
+     metal:use-macro="<macro-location>" 
+
+Our ``app_templates/index.pt`` can be that simple::
+
+    <html metal:use-macro="context/@@mymacros/mypage">
+    </html>
+
+Watching::
+
+	http://localhost:8080/test/index
+
+should now give the same result as above, although we didn't call
+``mymacros`` in browser, but ``index``. That's what macros are made
+for.
+
+When we fill the slots, we get different content rendered within
+the same macro. You can fill slots using
+
+    metal:fill-slot="<slot-name>"
+
+where the slot-name must be defined in the macro. Now, change
+``indext.pt`` to::
+
+    <html metal:use-macro="context/@@mymacros/mypage">
+      <body>
+        <div metal:fill-slot="body">
+          My content from index.pt
+        </div>
+      </body>
+    </html>
+
+and you will get the output::
+
+    The content:
+    My content from index.pt
+
+The pattern of the macro reference (the <macro-location>) used here
+is::
+
+    context/<view-name>/<macro-name>
+
+whereas ``context`` references the object being viewed, which in our
+case is the ``Sample`` application. In plain English we want Zope to
+look for a view for a ``Sample`` application object (``test``) which
+is called ``mymacros`` and contains a macro called ``mypage``.
+
+The logic behind this is, that views are always registered for certain
+object types. Registering a view with some kind of object (using
+``grok.context()`` for example), means, that we promise, that this
+view can render objects of that type. (It is up to you to make sure,
+that the view can handle rendering of that object type).
+
+It is not a bad idea to register views for interfaces (instead of
+implementing classes), because it means, that a view will remain
+usable, while an implementation of an interface can change. [FIXME: Is
+this a lie?] This is done in the section `Defining 'all-purpose'
+macros`_ below.
+
+
+Background: how ``grok.View`` and macros interact
+-------------------------------------------------
+
+In case of ``grok.View`` views are in fact ``BrowserPage`` objects
+with an attribute ``template``, which is the associated page
+template. The associated page template in turn has got an attribute
+``macros``, which is a dictionary containing all the macros defined in
+the page template with their names as keys (or ``None``). 
+
+This means, that you can also reference a macro of a ``grok.View``
+using::
+
+     context/<view-name>/template/macros/<macro-name>
+
+Grok shortens this path for you by mapping the ``macros`` dictionary
+keys to the associated ``grok.View``. If you define a macro
+``mymacro`` in a template associated with a ``grok.View`` called
+``myview``, this view will map ``mymacro`` as an own attribute, so
+that you can ask for the attribute ``mymacro`` of the *view*, wheras
+it is in fact an attribute of the associated template.
+
+Such, you can write in short for the above pattern::
+
+      context/<view-name>/<macro-name>
+
+View names always start with the 'eyes' (``@@``) which is a shortcut
+for ``++view++<view-name>``.
+
+
+Defining 'all-purpose' macros
+------------------------------
+
+To define an 'all-purpose' macro, i.e. a macro, that can render
+objects of (nearly) any type and thus be accessed from any
+other page template, just set a very general context for your macro
+view::
+
+    from zope.interface import Interface
+    import grok
+
+    class Master(grok.View):
+        grok.context(Interface)
+
+and reference the macros of the associated pagetemplate like this::
+
+    context/@@master/<macro-name>
+
+Because the macros in ``Master`` now are 'bound' (in fact their view
+is bound) to ``Interface`` and every Grok application, model or
+container implements some interface, the ``Master`` macros will be
+accessible from nearly every other context. ``Master`` promises to be
+a view for every object, which implements ``Interface``.
+
+
+Accessing Zope3 standard macros
+-------------------------------
+
+The standard macros of Zope 3, which render also the default ZMI
+pages, are accessible under the view-name ``standard_macros`` and usually
+provide slots ``title``, ``headers`` and ``body``. It is
+good style to provide this slots with your homegrown views as well.
+
+To give your pages standard Zope3 look, you can do something like
+this in your page template::
+
+        <html metal:use-macro="context/@@standard_macros/page">
+          <head>
+            <title metal:fill-slot="title">
+              Document Title
+            </title>
+            <metal:headers fill-slot="headers">
+              <!-- Additional headers here... -->
+            </metal:headers>
+          </head>
+          <body>
+            <div metal:fill-slot="body">
+              Your content here...
+            </div>
+          </body>
+        </html>
+

Modified: Sandbox/ulif/grok-adminui/doc/tutorial.txt
===================================================================
--- Sandbox/ulif/grok-adminui/doc/tutorial.txt	2007-07-12 13:55:41 UTC (rev 77741)
+++ Sandbox/ulif/grok-adminui/doc/tutorial.txt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -78,14 +78,15 @@
 
   .. _`ez_setup.py`: http://peak.telecommunity.com/dist/ez_setup.py
 
-  This will make ``easy_install`` available to you.
+  This will make ``easy_install-2.4`` available to you.
 
   **Note**: Sometimes you have ``easy_install`` installed but you need
   a newer version of the underlying setuptools infrastructure to make
   Grok work. You can automatically upgrade setuptools this by doing::
 
-    $ sudo easy_install -U setuptools
+    $ sudo easy_install-2.4 -U setuptools
 
+
 Setting up grok on a Unix-like (Linux, Mac OS X) environment is
 easy. 
 
@@ -116,6 +117,7 @@
 
   $ grokproject Sample
 
+
 This tells grokproject to create a new subdirectory called ``Sample``
 and set up the project in there. grokproject will automatically
 download and install Zope 3 and Grok into the project area.
@@ -123,6 +125,39 @@
 .. XXX when grokproject gains a switch for pointing to a shared egg
        directory, mention this here.
 
+.. sidebar:: Problems running ``grokproject``
+
+  During the run of ``grokproject`` many things can go wrong. Problems
+  that happen easily:
+
+  * No subversion installed
+
+    If you don't have a Zope 3 installation already installed, you need
+    ``Subversion`` installed on the computer, where you want to run
+    ``grokproject``, because the sources of Zope 3 are fetched from a
+    subversion repository during install. Visit the `Subversion site`_
+    to get an appropriate ``Subversion`` client.
+
+    .. _`Subversion site`: http://subversion.tigris.org/
+
+  * Missing ``mkzopeinstance``
+
+    The install of Grok might fail, complaining about a missing file
+    ``mkzopeinstance``. If this happens, it is likely, that you have a
+    configuration file ``.pydistutils.cfg`` in your home directory
+    containing a directive for where to install binaries. Disable this
+    directive putting a comment char (``#``) at the beginning of the
+    line which contains ``install_scripts``. Especially users of MacOS
+    X might encounter this problem. This can also happen, if you use
+    an already installed Zope 3.
+
+    For background information concerning this issue, have a look at
+    the `EasyInstall Custom Installation Locations`_ on the
+    EasyInstall site.
+
+    .. _`EasyInstall Custom Installation Locations`: http://peak.telecommunity.com/DevCenter/EasyInstall#mac-os-x-user-installation
+
+
 grokproject will tell you what it will be creating::
 
   Selected and implied templates:
@@ -1301,7 +1336,37 @@
 From the perspective of Python, you can think of containers as
 dictionaries.  They allow item access (``container['key']``) to get at
 its contents. They also define methods such as ``keys()`` and
-``values()``. Containers do a lot more than Python dictionaries
+``values()``. 
+
+.. sidebar:: Containers are not dictionaries
+
+	     Although containers mainly behave like dictionaries, they
+	     are in fact ``BTrees``, balanced trees, which makes them
+	     (beside other advantages) capable of maintaining really
+	     large amounts of objects in an efficient manner. The
+	     difference to ordinary dictionaries counts, where you
+	     want to do something like this::
+
+	        for key in mycontainer.keys(): 
+		     do_something(mycontainer[key])
+
+	     The thing returned by the call to ``keys()`` is *not* a
+	     list (as it is, when you call a dictionarys ``keys()``
+	     method), but an iterable. On each loop the mycontainers
+	     ``next()`` method is called to get the next key. So, if
+	     you, for example, change the number of elements stored in
+	     the container while calling ``do_something()``, you
+	     easily run into trouble. Especially calling
+	     ``del(mycontainer[key])`` will not do, what you might
+	     expect. Instead do the following::
+
+	        for key in list(mycontainer.keys()):
+		     del(mycontainer[key])
+
+             Such, using the ``list()`` function, you get a list of
+             keys instead of an iterable.
+
+Containers do a lot more than Python dictionaries
 though: they are persistent, and when you modify them, you don't have
 to use `_p_changed` anywhere to notice you changed them. They also
 send out special events that you can listen to when items are placed
@@ -1373,3 +1438,95 @@
 instances of ``Entry``, but also other containers. If you made those
 modifications, you would be on your way to building your own content
 management system with Grok.
+
+
+Building forms with formlib
+===========================
+
+Up to now, we created forms using basically plain HTML and
+implementing every apect of 'logic' using Python code. This is fine
+for some cases but often you would like to have a more automatic way
+to create forms. There is still a lot of repetition in the code. For
+instance we tell several times what values we would like to
+edit/display and what kind of data we would like to have stored
+therein. Furthermore, when the model we use changes slightly, we have
+to maintain a lot of associated logic. Every piece of validation code
+has to be reviewed and eventually rewritten. Last not least you cannot
+easily reuse your existing validation for other models, where you have
+a similar kind of data. 
+
+It would be nice, if we could just tell what kind of data we
+have and get appropriate forms without too much hassle. This is
+possible with grok and it is easy.
+
+.. sidebar:: `zope.formlib`: the name of the magic behind forms.
+
+
+  Grok does nearly nothing to provide the magic of forms as discussed
+  here. Instead it makes use of a package quite popular in Zope 3, the
+  `zope.formlib` package.
+
+  You can learn more about ``formlib`` in the documentation, which
+  comes with the package itself:
+
+    http://svn.zope.org/zope.formlib/trunk/src/zope/formlib/form.txt
+
+
+In Grok the creation of forms is supported by special form objects:
+``grok.EditForm``, ``grok.DisplayForm`` and ``grok.AddForm``. These
+are in fact ``grok.Views`` as well, but offer in addition a special
+machinery, which helps you to generate forms (in extreme) without even
+a single line of HTML code.
+
+
+Let's create a simple Form using ``grok.EditForm``. For that purpose
+we start with the application as coded above in section `Storing
+data`_ but we turn the ``Edit`` class in ``app.py``, which is a
+``grok.View`` into a ``grok.EditForm`` and import a ``schema`` called
+``TextLine`` at the beginning:
+
+.. include:: groktut/building_forms_with_formlib/src/sample/app.py
+  :literal:
+
+When you view the edit form of this application going to
+
+  http://localhost:8080/test/edit
+
+you will see an input field labeled `Text to store:` and a button
+entitled `Store`. This is nothing new. Ugh? What happened? The reason
+is, that there is still a template ``edit.pt`` associated with our new
+form, which renders the form the good old fashioned way and makes no
+use at all from our new class. You *can* specify page templates to
+render the output of forms, just as you can do with ordinary
+``grok.View``, but you don't have to. Now remove the page template
+``edit.pt``.
+
+  $ rm app_templates/edit.pt
+
+and restart your Zope instance.
+
+When you look again at
+
+  http://localhost:8080/test/edit
+
+you should be able to notice some changes: There will be an asterisk
+(`*`) in front of the field label, indicating that this field is a
+required one. The text of the submit button should have turned to
+`Apply`. This is the look of a form that was completely
+autogenerated. Note, that we didn't write one line of HTML to get a
+complete form. And it works.
+
+If you leave the text in the field untouched and click the `Apply`
+button, you will get a message on top, telling you that there were no
+changes.
+
+If you change the text and apply a new value, the form will display a
+timestamp instead, telling that the data was
+updated. Congratulations. You created your first *real* form with
+Grok. Looking back to the first forms created above, they appear
+nowmere as some conglomeration of Python code and HTML wich just
+accidently happens to be a HTML form.
+
+Defining field types using schemas
+----------------------------------
+

Modified: Sandbox/ulif/grok-adminui/src/grok/admin/README.txt
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/README.txt	2007-07-12 13:55:41 UTC (rev 77741)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/README.txt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -1,6 +1,9 @@
 A basic grok admin UI
-====================
+=====================
 
+The internal name of the admin UI is:
+Grok Application Interface Application or, for short gaia.
+
 Overview
 --------
 
@@ -11,3 +14,29 @@
 
 * "Delete application" form: checkboxes displayed with listed installed
   applications. Selected items may be deleted.
+
+
+To Do
+-----
+
+* Better application handling
+
+  - Configure apps.
+
+* Maintenance tools
+
+  - Start/stop/restart Zope3.
+
+* Debugging tools
+
+  - Show error logs.
+
+* Introspection tool
+
+  - Give information concerning installed apps, their containers
+    and contained objects.
+
+* Nicer layout
+
+* AJAXification using some framework (MojiKit or KSS most probably)
+

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/docgrok.py (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/docgrok.py)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/docgrok.py	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/docgrok.py	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,560 @@
+"""The Grok's Friendly Doctor.
+
+Ask DocGrok and he will try his best, to keep you well informed about
+everything hanging around in your Zope3 and your Grok Application.
+"""
+
+import zope.component
+from zope.app.folder.interfaces import IRootFolder
+from zope.dottedname.resolve import resolve
+from zope.interface.interface import InterfaceClass
+from zope.security.proxy import isinstance
+from zope.proxy import removeAllProxies
+
+import os
+import sys # for sys.path
+import types
+import grok
+import inspect
+import grok.interfaces
+from grok.interfaces import IApplication
+from martian.scan import is_package, ModuleInfo
+from martian import InstanceGrokker, ModuleGrokker
+
+from zope.app.i18n import ZopeMessageFactory as _
+
+from zope.app.apidoc.codemodule.module import Module
+from zope.app.apidoc.codemodule.class_ import Class
+from zope.app.apidoc.codemodule.text import TextFile
+from zope.app.apidoc.utilities import renderText
+
+grok.context(IRootFolder)
+grok.define_permission('grok.ManageApplications')
+
+def find_filepath( dotted_path ):
+    """Find the filepath for a dotted name.
+
+    If a dotted name denotes a filename we try to find its path
+    by concatenating it with the system paths and looking for an
+    existing file. Every dot in the filename thereby can be part
+    of the filename or of its path. Therefore we check the
+    several possible dirname/filename combinations possible.
+
+    Returns None if no suitable filepath can be found.
+
+    This functions does *not* look for Python elements like classes,
+    interfaces and the files where they were defined. Use `resolve()`
+    and the `__file__` attribute for examining this kind of stuff
+    instead.
+
+    This function finds the location of text files and the like, as
+    far as they are placed inside some Python path.
+    """
+    currpath = dotted_path
+    currname = ""
+    while '.' in currpath:
+        currpath, name = currpath.rsplit('.', 1)
+        if currname != "":
+            currname = "." + currname
+        currname = name + currname
+        tmp_path = ""
+        for elem in currpath.split( '.' ):
+            tmp_path = os.path.join( tmp_path, elem )
+        for syspath in sys.path:
+            filepath_to_check = os.path.join(syspath, tmp_path, currname)
+            if os.path.isfile(filepath_to_check):
+                return filepath_to_check
+    return None
+
+
+def handle_module( dotted_path, ob=None ):
+    """Determine, whether the given path/obj references a Python module.
+    """
+    if ob is None:
+        try:
+            ob = resolve( dotted_path )
+        except ImportError:
+            return None
+    if not hasattr(ob, '__file__'):
+        return None
+    if not is_package(os.path.dirname(ob.__file__)):
+        return None
+    if os.path.basename(ob.__file__) in ['__init__.py',
+                                         '__init__.pyc',
+                                         '__init__.pyo']:
+        return None
+    return DocGrokModule(dotted_path)
+
+def handle_package( dotted_path, ob=None):
+    """Determine, whether the given path/obj references a Python package.
+    """
+    if ob is None:
+        try:
+            ob = resolve( dotted_path )
+        except ImportError:
+            return None
+    if not hasattr(ob, '__file__'):
+        return None
+    if not is_package(os.path.dirname(ob.__file__)):
+        return None
+    if os.path.basename(ob.__file__) not in ['__init__.py',
+                                             '__init__.pyc',
+                                             '__init__.pyo']:
+        return None
+    return DocGrokPackage(dotted_path)
+
+def handle_interface(dotted_path, ob=None):
+    """Determine, whether the given path/obj references an interface.
+    """
+    if ob is None:
+        try:
+            ob = resolve(dotted_path)
+        except ImportError:
+            return None
+    if not isinstance(
+        removeAllProxies(ob), InterfaceClass):
+        return None
+    return DocGrokInterface(dotted_path)
+
+def handle_class(dotted_path, ob=None):
+    """Determine, whether the given path/obj references a Python class.
+    """
+    if ob is None:
+        try:
+            ob = resolve(dotted_path)
+        except ImportError:
+            return None
+    if not isinstance(ob, (types.ClassType, type)):
+        return None
+    return DocGrokClass(dotted_path)
+
+def handle_grokapplication( dotted_path, ob=None):
+    """Determine, whether the given path/obj references a Grok application.
+    """
+    if ob is None:
+        try:
+            ob = resolve(dotted_path)
+        except ImportError:
+            None
+    if not IApplication.implementedBy( ob ):
+        return None
+    return DocGrokGrokApplication(dotted_path)
+
+def handle_textfile( dotted_path, ob=None):
+    if ob is not None:
+        # Textfiles that are objects, are not text files.
+        return None
+    if os.path.splitext( dotted_path )[1] != u'.txt':
+        return None
+    return DocGrokTextFile(dotted_path)
+
+# The docgroks registry.
+#
+# We register 'manually', because the handlers
+# are defined in the same module.
+docgrok_handlers = [
+    { 'name' : 'module',
+      'handler' : handle_module },
+    { 'name' : 'package',
+      'handler' : handle_package },
+    { 'name' : 'interface',
+      'handler' : handle_interface },
+    { 'name' : 'grokapplication',
+      'handler' : handle_grokapplication },
+    { 'name' : 'class',
+      'handler' : handle_class },
+    { 'name' : 'textfile',
+      'handler' : handle_textfile}]
+
+
+def handle(dotted_path):
+    """Find a doctor specialized for certain things.
+    """
+    try:
+        ob = resolve( dotted_path )
+    except ImportError:
+        # There is no object of that name. Give back 404.
+        # XXX Do something more intelligent, offer a search.
+        if not find_filepath( dotted_path ):
+            return None
+        ob = None
+    except:
+        return None
+
+    for handler in docgrok_handlers:
+        spec_handler = handler['handler']
+        doc_grok = spec_handler( dotted_path, ob )
+        if doc_grok is None:
+            continue
+        return doc_grok
+    return DocGrok(dotted_path)
+
+class DocGrokGrokker(InstanceGrokker):
+    """A grokker that groks DocGroks.
+
+    This grokker can help to 'plugin' different docgroks in an easy
+    way. You can register docgroks for your special classes, modules,
+    things. All required, is a function, that determines the correct
+    kind of thing, you like to offer a docgrok for and returns a
+    specialized docgrok or None (in case the thing examined is not the
+    kind of thing your docgrok is a specialist for).
+
+    Unfortunately, order counts here. If one docgrok handler is able
+    to deliver a specialized docgrok object, no further invesitgation
+    will be done.
+
+    In principle, the following should work. First we import the
+    docgrok module, because it contains a more specific grokker: the
+    InstanceGrokker 'docgrok_grokker' ::
+
+      >>> from grok.admin import docgrok
+
+    Then we get create an (empty) 'ModuleGrokker'. 'ModuleGrokkers'
+    can grok whole modules. ::
+      
+      >>> from martian import ModuleGrokker
+      >>> module_grokker = ModuleGrokker()
+
+    Then we register the 'docgrok_grokker', which should contain some
+    base handlers for modules, classes, etc. by default::
+      
+      >>> module_grokker.register(docgrok.docgrok_grokker)
+
+    The 'docgrok_grokker' is an instance of 'DocGrokGrokker'::
+
+      >>> from grok.admin.docgrok import DocGrokGrokker
+      >>> isinstance(docgrok.docgrok_grokker, DocGrokGrokker)
+      True
+
+    Now imagine, you have your own DocGroks for special things, for
+    example for a class 'Mammoth'. You might have derived this class
+    from DocGrok (or a subclass thereof), but this is not a
+    requirement. Note however, that other programmers might expect
+    your DocGroks to be compatible in a certain manner, so it surely
+    is a good idea to derive your GrokDocs from the original one.
+
+    Let's assume, your DocGrokMammoth is defined in a module called
+    'mammoth'::
+
+      >>> from grok.admin.docgrok import DocGrok
+      >>> class mammoth(FakeModule):
+      ...   class Mammoth(object):
+      ...     pass
+      ...
+      ...   class MammothDocGrok(DocGrok):
+      ...     def isMammoth(self):
+      ...       return True
+      ...
+      ...   def handle_mammoths(dotted_path,ob=None):
+      ...     if not isinstance(ob, Mammoth):
+      ...       return None
+      ...     return MammothDocGrok(dotted_path)
+
+    This is a simple DocGrok ('MammothDocGrok') accompanied by a
+    thing, it is representing (class 'Mammoth') and a handler
+    function, which decides, whether a given dotted path denotes a
+    Mammoth or not. The FakeModule class is a workaround to emulate
+    modules in doctests. Just think of watching a module, when you see
+    a FakeModule class.
+
+    Now we want to register this new DocGrok with the 'global
+    machinery'. Easy::
+    
+      >>> module_grokker.grok( 'mammoth_grokker', mammoth )
+      True
+      
+    Now the 'handle_mammoths' function is considered to deliver a
+    valid DocGrok, whenever it is asked. Every time, someone asks the
+    docgroks 'handle()' function for a suitable docgrok for things
+    that happen to be Mammoths, a DocGrokMammoth will be served.
+
+    Even the default docgrok viewer that comes with the grok package
+    in the admin interface, now will deliver your special views for
+    mammoths (if you defined one; otherwise the default 'DocGrok'
+    template will be used to show mammoth information).
+
+    XXX TODO: Show how to make a docgrok view.
+
+    That's it.
+    
+    """
+    component_class = types.FunctionType
+
+    def grok(self, name, obj, **kw):        
+        if not name.startswith('handle_'):
+            return False
+        if name in [x['name'] for x in docgrok_handlers]:
+            return False
+        #docgrok_handlers[name] = obj
+        docgrok_handlers.insert( 0, {'name':name,
+                                     'handler':obj})
+        return True
+
+    
+class DocGrok(grok.Model):
+    """DocGrok helps us finding out things about ourselves.
+
+    There are DocGroks for packages, modules, interfaces, etc., each
+    one a specialist for a certain type of element. 'Pure' DocGroks
+    build the root of this specialist hierarchy and care for objects,
+    which can not be handled by other, more specialized DocGroks.
+
+    DocGrok offers a minimum of information but can easily be extended in
+    derived classes.
+    """
+    msg = "I am Dr. Grok. How can I help you?"
+    path = None
+    _traversal_root = None
+    #_children = {}
+
+    def __init__(self, dotted_path ):
+        #super( DocGrok, self ).__init__()
+        self.path = dotted_path
+
+    def getPath(self):
+        return self.path
+
+    def getMsg(self):
+        return self.msg
+
+    def getFilePath( self ):
+        try:
+            ob = resolve( self.path )
+            return hasattr(ob, __file__) and os.path.dirname(ob.__file__) or None
+        except ImportError:
+            pass
+        return find_filepath(self.path)
+
+    def getDoc(self, heading_only=False):
+        """Get the doc string of the module STX formatted.
+        """
+        if hasattr( self, "apidoc") and hasattr(
+            self.apidoc, "getDocString" ):
+            text = self.apidoc.getDocString()
+        else:
+            return None
+        if text is None:
+            return None
+        lines = text.strip().split('\n')
+        if len(lines) and heading_only:
+            # Find first empty line to separate heading from trailing text.
+            headlines = []
+            for line in lines:
+                if line.strip() == "":
+                    break
+                headlines.append(line)
+            lines = headlines
+        # Get rid of possible CVS id.
+        lines = [line for line in lines if not line.startswith('$Id')]
+        return renderText('\n'.join(lines), self.path)
+
+
+    def traverse(self,patient):
+        """ Do special traversing inside the surgery.
+
+        Inside the docgrok-'namespace' we only accept DocGroks and
+        colleagues. Each DocGrok cares for a patient represented by a
+        path. This path might denote an object in the ZODB or in the
+        python path.
+
+        """
+        if patient == "index.html":
+            return self
+        if self.path is None:
+            newpath = patient
+        else:
+            newpath = '.'.join([self.path, patient])
+
+        #doctor = getDocGrokForDottedPath( newpath )
+        doctor = handle( newpath )
+
+        if doctor is None:
+            # There is nothing of that name. Give back 404.
+            # XXX Do something more intelligent, offer a search.
+            return None
+        #doctor.msg = "Do more grokking!"
+        doctor.__parent__ = self
+        doctor.__name__ = patient
+        doctor._traversal_root = self._traversal_root
+        doctor.path = newpath
+        return doctor
+    pass
+
+class DocGrokTraverser(grok.Traverser):
+    """If first URL element is 'docgrok', handle over to DocGrok.
+
+    This traverser binds to the RootFolder, which means, it is only
+    asked, when the publisher looks for elements in the Zope root (or
+    another IRootFolder). The further traversing is done by the Docs'
+    own traverser in it's model. See method `traverse()` in DocGrok.
+    """
+    grok.context(IRootFolder)
+
+    def traverse(self,path):
+        if path == "docgrok":
+            doctor = DocGrok(None)
+            # Giving a __parent__ and a __name__, we make things
+            # locatable in sense of ILocatable.
+            doctor.__parent__ = self.context
+            doctor.__name__ = 'docgrok'
+            doctor._traversal_root = doctor
+            return doctor
+        return None
+
+
+class DocGrokPackage(DocGrok):
+    """This doctor cares for python packages.
+    """
+    msg = "I am a Package of the Doc"
+    path=None
+    apidoc = None
+    _traversal_root = None
+
+    def __init__(self,dotted_path):
+        self.path = dotted_path
+        self._module = resolve(self.path)
+        # In apidoc packages are handled like modules...
+        self.apidoc = Module( None, None, self._module, True)
+
+    def getDocString( self ):
+        return self.apidoc.getDocString()
+
+    def getFilePath( self ):
+        ob = resolve( self.path )
+        return os.path.dirname( ob.__file__ ) + '/'
+
+    def _getModuleInfos( self, filter_func=lambda x:x ):
+        """Get modules and packages of a package.
+
+        The filter function will be applied to a list of modules and
+        packages of type grok.scan.ModuleInfo.
+        """
+        ob = resolve( self.path )
+        filename = ob.__file__
+        module_info = ModuleInfo( filename, self.path )
+        infos = module_info.getSubModuleInfos()
+        if filter_func is not None:
+            infos = filter( filter_func, infos)
+        #infos = [x for x in infos if not x.isPackage()]
+        result = []
+        for info in infos:
+            subresult = {}
+            # Build a url string from dotted path...
+            mod_path = "docgrok"
+            for path_part in info.dotted_name.split('.'):
+                mod_path = os.path.join( mod_path, path_part )
+            subresult = {
+                'url' : mod_path,
+                'name' : info.name,
+                'dotted_name' : info.dotted_name
+                }
+            result.append( subresult )
+        return result
+        
+
+    def getModuleInfos( self ):
+        """Get the modules inside a package.
+        """
+        filter_func = lambda x: not x.isPackage()
+        return self._getModuleInfos( filter_func )
+
+    def getSubPackageInfos( self ):
+        """Get the subpackages inside a package.
+        """
+        filter_func = lambda x: x.isPackage()
+        return self._getModuleInfos( filter_func )
+
+    def getTextFiles( self ):
+        """Get the text files inside a package.
+        """
+        filter_func = lambda x: x.isinstance( TextFile )
+        return self._getModuleInfos( filter_func )
+
+    def getChildren( self ):
+        result = self.apidoc.items()
+        result.sort( lambda x,y:cmp(x[0], y[0]) )
+        return result
+
+
+
+class DocGrokModule(DocGrokPackage):
+    """This doctor cares for python modules.
+    """
+
+    def getFilePath( self ):
+        ob = resolve( self.path )
+        filename = ob.__file__
+        if filename.endswith('o') or filename.endswith('c'):
+            filename = filename[:-1]
+        return filename
+
+       
+class DocGrokClass(DocGrokPackage):
+    """This doctor cares for classes.
+    """
+    def __init__(self,dotted_path):
+        self.path = dotted_path
+        self.klass = resolve(self.path)
+        self.module_path, self.name = dotted_path.rsplit('.',1)
+        self.module = resolve( self.module_path )
+        mod_apidoc = Module( None, None, self.module, False)
+        self.apidoc = Class( mod_apidoc, self.name, self.klass)
+
+    def getFilePath( self ):
+        if not hasattr( self.module, "__file__" ):
+            return None
+        filename = self.module.__file__
+        if filename.endswith('o') or filename.endswith('c'):
+            filename = filename[:-1]
+        return filename
+
+class DocGrokInterface(DocGrokClass):
+    """This doctor cares for interfaces.
+    """
+    def __init__(self,dotted_path):
+        self.path = dotted_path
+        self.klass = resolve(self.path)
+        self.module_path, self.name = dotted_path.rsplit('.',1)
+        self.module = resolve( self.module_path )
+        mod_apidoc = Module( None, None, self.module, False)
+        self.apidoc = Class( mod_apidoc, self.name, self.klass)
+
+    def getFilePath( self ):
+        if not hasattr( self.module, "__file__" ):
+            return None
+        filename = self.module.__file__
+        if filename.endswith('o') or filename.endswith('c'):
+            filename = filename[:-1]
+        return filename
+
+class DocGrokGrokApplication(DocGrokClass):
+    """This doctor cares for Grok applications and components.
+    """
+    pass
+
+class DocGrokTextFile(DocGrok):
+    """This doctor cares for text files.
+    """
+
+    def __init__(self,dotted_path):
+        self.path = dotted_path
+        self.filepath = find_filepath( self.path )
+        self.filename = os.path.basename( self.filepath )
+
+
+    def getPackagePath(self):
+        """Return package path as dotted name.
+        """
+        #return os.path.dirname( self.filepath )
+        dot_num_in_filename = len([x for x in self.filename if x == '.'])
+        parts = self.path.rsplit('.', dot_num_in_filename + 1)
+        return parts[0]
+
+    def getContent(self):
+        """Get file content UTF-8 encoded.
+        """
+        file = open(self.filepath, 'rU')
+        content = file.read()
+        file.close()
+        return content.decode('utf-8')
+

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/docgrok.txt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/docgrok.txt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/docgrok.txt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/docgrok.txt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,100 @@
+=======
+DocGrok
+=======
+
+The Grok's personal doctor.
+
+What is it?
+-----------
+
+DocGrok is meant as a friendly extension of the Zope 3 'builtin'
+apidoc feature. It should be easy to handle and informative in
+content. Main target are developers new to Grok.
+
+DocGrok is there to generate documentation for nearly everything
+living in a running Zope 3 instance.
+
+How to Use it
+-------------
+
+DocGrok documentation can be accessed through the web, calling special
+URL paths in your Zope 3 instance or (surprise!) directly via Python.
+
+
+Calling DocGrok through the web
++++++++++++++++++++++++++++++++
+
+To get documentation about a special element, call docgrok simply with
+`docgrok` as first part of the URL path.
+
+For example documentation about the grok package can be reached using
+
+    http://localhost:8080/docgrok/grok
+
+The admin package, which is located in the grok package can be
+accessed directly such:
+
+    http://localhost:8080/docgrok/grok/admin
+
+
+Calling the doctor directly
++++++++++++++++++++++++++++
+
+The doctor can also be reached via Python, naturally.
+
+   >>> from grok.admin import docgrok
+   >>> doctor = docgrok.DocGrok('grok.admin.docgrok')
+
+This doctor has immediatly a patient, which is denoted by the dotted
+path `grok.admin.docgrok`. The dotted path might reference any thing
+which lives in the Python environment: a package, a module, a class, a
+function or even a file or some interface attribute.
+
+   >>> doctor.getPath()
+   'grok.docgrok'
+
+We can also get a filepath, using the `getFilePath()` method. Objects,
+which have no filepath always return `None`.
+
+There is not much more information to get from Doc Grok. This is,
+because a `DocGrok` only knows very little about the objects. The base
+doc is not a specialist, but cares for all objects and elements, which
+can not be handled by other specialists.
+
+If we like to get more detailed information, we have to call a
+specialist. For example a package doctor, who happens to be called
+`DocGrokPackage`: 
+
+    >>> doctor = DocGrokPackage('grok.admin')
+
+
+    >>> doctor.path = 'grok.admin'
+    >>> doctor.getPath()
+    'grok.admin'
+
+Fine. Obviously DocGrokPackages know as much as DocGroks. That's
+little. But a package knows about package-things too:
+
+    >>> info = doctor.getSubPackageInfo()
+
+will generate infos concerning subpackages in the package formerly
+set.
+
+
+Getting a specialist directly
++++++++++++++++++++++++++++++
+
+Often we don't want to visit the base doctor, but a specialist
+directly. But how can we tell, what specialist we need? Easy. We use
+the function getDocGrokForDottedPath which delivers us a doctor, who
+can tell us more:
+
+    >>> from grok.admin.docgrok import getDocGrokForDottedPath
+    >>> thedoc = getDocGrokForDottedPath( 'grok.admin.docgrok' )
+    >>> type( thedoc )
+    <class 'grok.admin.docgrok.DocGrokModule'>
+
+This is correct. `docgrok` is a python module, so the best specialist
+we can get is a `DocGrokModule`. The mentioned function therefore is
+some kind of factory, which always gives us a doctor most appropriate
+for the kind of thing specified by a dotted path.

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/static (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/static)

Modified: Sandbox/ulif/grok-adminui/src/grok/admin/view.py
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view.py	2007-07-12 13:55:41 UTC (rev 77741)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view.py	2007-07-12 14:07:50 UTC (rev 77742)
@@ -1,36 +1,344 @@
+import grok
+import os
+from grok.admin.docgrok import DocGrok, DocGrokPackage, DocGrokModule
+from grok.admin.docgrok import DocGrokClass, DocGrokInterface, DocGrokGrokApplication
+from grok.admin.docgrok import DocGrokTextFile
+
 import zope.component
-import grok.interfaces
 from zope.app.folder.interfaces import IRootFolder
 
+from zope.app import zapi
+from zope.app.applicationcontrol.interfaces import IServerControl
+from zope.app.applicationcontrol.applicationcontrol import applicationController
+from zope.app.applicationcontrol.runtimeinfo import RuntimeInfo
+from zope.app.applicationcontrol.browser.runtimeinfo import RuntimeInfoView
+
+from zope.interface.interface import InterfaceClass
+from zope.app.apidoc import utilities, codemodule
+from zope.app.apidoc.utilities import getPythonPath, renderText, columnize
+from zope.app.apidoc.codemodule.module import Module
+from zope.app.apidoc.codemodule.class_ import Class
+from zope.app.apidoc.codemodule.function import Function
+from zope.app.apidoc.codemodule.text import TextFile
+from zope.app.apidoc.codemodule.zcml import ZCMLFile
+
+from zope.proxy import removeAllProxies
+
 grok.context(IRootFolder)
 grok.define_permission('grok.ManageApplications')
 
-class Index(grok.View):
-    grok.name('index.html') # the root folder isn't a grok.Model
-    grok.require('grok.ManageApplications')
 
-    def update(self):
-        apps = zope.component.getAllUtilitiesRegisteredFor(
-            grok.interfaces.IApplication)
-        self.applications = ("%s.%s" % (x.__module__, x.__name__)
-                             for x in apps)
+class Add(grok.View):
 
-class Add(grok.View):
     grok.require('grok.ManageApplications')
 
-    def render(self, application, name):
+    def update(self, inspectapp=None, application=None):
+        if inspectapp is not None:
+            self.redirect( self.url("docgrok") + "/%s/index"%(application.replace('.','/'),))
+        return 
+
+    def render(self, application, name, inspectapp=None):
+        if name is None or name == "":
+            self.redirect(self.url(self.context))
+            return
         app = zope.component.getUtility(grok.interfaces.IApplication,
                                         name=application)
         self.context[name] = app()
         self.redirect(self.url(self.context))
 
+
 class Delete(grok.View):
+
     grok.require('grok.ManageApplications')
 
-    def render(self, items):
+    def render(self, items=None):
+        if items is None:
+            self.redirect(self.url(self.context))
+            return
         if not isinstance(items, list):
             items = [items]
         for name in items:
             del self.context[name]
         self.redirect(self.url(self.context))
 
+
+class GAIAView(grok.View):
+    """A grok.View with a special application_url.
+
+    We have to compute the application_url different from common
+    grok.Views, because we have no root application object in the
+    adminUI. To avoid mismatch, we also call it 'root_url'.
+
+    """
+
+    def root_url(self, name=None):
+        obj = self.context
+        result = ""
+        while obj is not None:
+            if __grok_context__.providedBy(obj):
+                return self.url(obj, name)
+            obj = obj.__parent__
+        raise ValueError("No application nor root element found.")
+
+    def in_docgrok(self):
+        return '/docgrok/' in self.url()
+
+
+class Index(GAIAView):
+    """A redirector to the real frontpage."""
+
+    grok.name('index.html') # The root folder is not a grok.Model
+    grok.require('grok.ManageApplications')
+
+    def update(self):
+        apps = zope.component.getAllUtilitiesRegisteredFor(
+            grok.interfaces.IApplication)
+        self.applications = ("%s.%s" % (x.__module__, x.__name__)
+                             for x in apps)
+        # Go to the first page immediately.
+        self.redirect(self.url('appsindex'))
+
+
+class AppsIndex(GAIAView):
+    """View for application management."""
+
+    grok.name('appsindex')
+    grok.require('grok.ManageApplications')
+
+    def getDocOfApp(self, apppath, headonly = True):
+        from grok.admin import docgrok
+        doctor = docgrok.handle(apppath)
+        result = doctor.getDoc(headonly)
+        if result is None:
+            result = ""
+        return result
+
+    def update(self):
+        apps = zope.component.getAllUtilitiesRegisteredFor(
+            grok.interfaces.IApplication)
+        inst_apps = [x for x in self.context.values()
+                     if hasattr(x, '__class__') and x.__class__ in apps]
+        self.applications = (
+          {'name': "%s.%s" % (x.__module__, x.__name__),
+           'docurl':("%s.%s" % (x.__module__, x.__name__)).replace( '.', '/')}
+          for x in apps)
+        self.installed_applications = inst_apps
+
+
+class Z3Index(GAIAView):
+    """Zope3 management screen."""
+
+    grok.name('z3index')
+    grok.require('grok.ManageApplications')
+
+    riv = RuntimeInfoView()
+
+    def serverControl(self):
+        return zapi.getUtility(IServerControl)
+
+    def runtimeInfo(self):
+        self.riv.context = applicationController
+        return self.riv.runtimeInfo()
+
+    def update(self, time=None, restart=None, shutdown=None):
+        self.ri = self.runtimeInfo()
+
+        if time is None:
+            return
+        try:
+            time = int(time)
+        except:
+            return
+        control = self.serverControl()
+        if restart is not None:
+            control.restart(time)
+        elif shutdown is not None:
+            control.shutdown(time)
+        self.redirect(self.url())
+
+
+class Macros(GAIAView):
+    """Provides the o-wrap layout."""
+
+    grok.context(IRootFolder)
+
+
+class DocGrokView(GAIAView):
+
+    grok.context(DocGrok)
+    grok.name( 'index' )
+
+    def getDoc(self, text=None, heading_only=False):
+        """Get the doc string of the module STX formatted."""
+        if text is None:
+            return None
+            if (hasattr(self.context, "apidoc") and
+                hasattr(self.context.apidoc, "getDocString")):
+                text = self.context.apidoc.getDocString()
+            else:
+                return None
+        lines = text.strip().split('\n')
+        if len(lines) and heading_only:
+            # Find first empty line to separate heading from trailing text.
+            headlines = []
+            for line in lines:
+                if line.strip() == "":
+                    break
+                headlines.append(line)
+            lines = headlines
+        # Get rid of possible CVS id.
+        lines = [line for line in lines if not line.startswith('$Id')]
+        return renderText('\n'.join(lines), self.context.getPath())
+
+    def getDocHeading( self, text=None):
+        return self.getDoc( text, True)
+
+    def getPathParts(self, path=None):
+        """Get parts of a dotted name as url and name parts.
+        """
+        if path is None:
+            path = self.context.path
+        if path is None:
+            return None
+        result = []
+        part_path = ""
+        for part in path.split( '.' ):
+            name = part
+            if part_path != "":
+                name = "." + part
+            part_path += part
+            result.append( {
+                'name':name,
+                'url':"/docgrok/%s" % (part_path,)
+                })
+            part_path += "/"
+        return result
+
+    def getEntries( self, columns=True ):
+        """Return info objects for all modules and classes in the
+        associated apidoc container.
+
+        """
+        if (not hasattr(self.context, "apidoc") or
+            not hasattr(self.context.apidoc, "items")):
+            return None
+        entries = []
+        for name, obj in self.context.apidoc.items():
+            entry = {
+                'name': name,
+                'obj' : obj,
+                'path': getPythonPath(removeAllProxies(obj)),
+                'url' : u'',
+                'doc' : None,
+                'ispackage' : False,
+                'ismodule' : False,
+                'isinterface' : False,
+                'isclass' : False,
+                'isfunction' : False,
+                'istextfile' : False,
+                'iszcmlfile' : False,
+                'signature' : None
+                }
+            entry['url'] = "%s/%s" % (self.context.path.replace('.','/'), name)
+            if hasattr(obj,"getDocString"):
+                entry['doc'] = self.getDocHeading(obj.getDocString())
+            elif hasattr(obj, "getDoc") and isinstance(
+                removeAllProxies(obj), InterfaceClass):
+                entry['doc'] = self.getDocHeading(obj.getDoc())
+            if isinstance(obj, Class):
+                entry['isclass'] = True
+            elif isinstance(obj, TextFile):
+                entry['istextfile'] = True
+            elif isinstance(obj, ZCMLFile):
+                entry['iszcmlfile'] = True
+            elif isinstance(obj,Function):
+                entry['isfunction'] = True
+                if hasattr(obj, 'getSignature'):
+                    entry['signature'] = obj.getSignature()
+            elif (isinstance(obj,Module) and
+                  os.path.basename(obj.getFileName()) in
+                    ['__init.py__', '__init__.pyc', '__init__.pyo']):
+                entry['ispackage'] = True
+            elif isinstance(obj,Module):
+                entry['ismodule'] = True
+            entries.append(entry)
+
+        entries.sort(lambda x, y: cmp(x['name'], y['name']))
+        return entries
+
+    def update(self):
+        self.docgrok_root = self.context._traversal_root
+        self.app_root = self.docgrok_root.__parent__
+        pass
+
+
+class DocGrokPackageView(DocGrokView):
+
+    grok.context(DocGrokPackage)
+    grok.name( 'index' )
+
+
+class DocGrokModuleView(DocGrokView):
+
+    grok.context(DocGrokModule)
+    grok.name( 'index' )
+
+
+class DocGrokClassView(DocGrokView):
+
+    grok.context(DocGrokClass)
+    grok.name( 'index' )
+
+    def getBases(self):
+        return self._listClasses(self.context.apidoc.getBases())
+
+    def getInterfaces(self):
+        return self._listClasses(
+          [iface for iface in self.context.apidoc.getInterfaces()])
+
+    def _listClasses(self, classes):
+        info = []
+        for cls in classes:
+            unwrapped_cls = removeAllProxies(cls)
+            fullpath = getPythonPath(unwrapped_cls)
+            if not fullpath:
+                continue
+            path, name = fullpath.rsplit('.', 1)
+            info.append( {
+                'path': path or None,
+                'path_parts' : self.getPathParts( path ) or None,
+                'name': name,
+                'url': fullpath and fullpath.replace('.','/') or None,
+                'doc': self.getDocHeading( cls.__doc__ ) or None
+                })
+        return info
+
+
+class DocGrokInterfaceView(DocGrokClassView):
+
+    grok.context(DocGrokInterface)
+    grok.name( 'index' )
+
+
+class DocGrokGrokApplicationView(DocGrokClassView):
+
+    grok.context(DocGrokGrokApplication)
+    grok.name( 'index' )
+
+
+class DocGrokTextFileView(DocGrokView):
+
+    grok.context(DocGrokTextFile)
+    grok.name( 'index' )
+
+    def getContent(self):
+        lines = self.context.getContent()
+        if self.context.path.endswith('.stx'):
+            format = 'zope.source.stx'
+        else:
+            format = 'zope.source.rest'
+        return renderText(lines, format=format)
+
+    def getPackagePathParts(self):
+        return self.getPathParts(
+            self.context.getPackagePath())

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/appsindex.pt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/view_templates/appsindex.pt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/appsindex.pt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/appsindex.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,56 @@
+<html metal:use-macro="context/@@macros/gaia-page">
+  <div metal:fill-slot="content">
+
+    <form tal:define="apps context/values"
+	  tal:attributes="action string:${context/@@absolute_url}/delete"
+	  tal:condition="apps|nothing">
+      <fieldset
+	  tal:condition="python: len(view.installed_applications)">
+        <legend>Installed applications</legend>
+        <div tal:repeat="app view/installed_applications">
+	  <input type="checkbox" 
+		 class="checkbox" 
+                 tal:attributes="value app/__name__;
+				 name string:items" />
+	  <a tal:attributes="href string:${context/@@absolute_url}/${app/__name__}">
+	    <span tal:replace="app/__name__"/>
+	    (<span tal:replace="app/__class__/__name__"/>)
+	  </a>
+	  &nbsp;&nbsp;
+	</div>
+
+	<p>
+	  <input class="button" type="submit" value="Delete Selected"/></p>
+      </fieldset>
+    </form>
+    <fieldset>	
+      <legend>Add application</legend>
+
+      <div class="menu-box1"
+	   tal:repeat="app view/applications">
+	<form action="" tal:attributes="action string:${context/@@absolute_url}/add;
+                                        name python: app['name'].split('.')[-1]">
+	  <div class="menu-box2">
+	    <div class="menu-head1"><a href=""
+				       tal:attributes="href string:${context/@@absolute_url}/docgrok/${app/docurl}"
+				       tal:content="app/name">Application Name</a></div>
+	    <div class="menu-description1">
+	      <span tal:replace="structure python: view.getDocOfApp(app['name']) or ''">
+		Application description here.
+	      </span>
+	    </div>
+	    <div class="menu-box3">
+	      <label>Name your new app: <input type="text" name="name"/></label>
+	      <input type="hidden" name="application" value=""
+		     tal:attributes="value app/name" />
+	      <input class="button" type="submit" name="Add" value="Create"/>
+	    </div>
+	  </div>
+	</form>
+      </div>
+
+    </fieldset>
+
+  </div>
+
+</html>

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokclassview.pt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/view_templates/docgrokclassview.pt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokclassview.pt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokclassview.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,206 @@
+<html metal:use-macro="view/app_root/@@macros/gaia-page">
+  <head>
+    <title>DocGrok page title</title>
+  </head>
+  <body>
+    <div metal:fill-slot="content">
+
+      <h1>
+	Class
+	<span class="docgrok-pathvalue">
+	  <span class="docgrok-elemname1">
+	    <span tal:replace="context/name">ClassName</span>
+	  </span>
+	</span> in <span class="docgrok-pathvalue">
+	  <span tal:repeat="part python: view.getPathParts()[:-1]"><a href=""
+	       tal:attributes="href string:${view/root_url}${part/url}"
+	       tal:content="part/name">part</a></span></span> (Python Class)
+      </h1>
+      <div class="docgrok-entry" 
+	   tal:content="structure python: view.getDoc(context.getDocString())">
+	Documentation string.
+      </div>
+      <div>
+	<h2>Paths</h2>
+
+	<div class="docgrok-entry">
+	  <span class="docgrok-description1">Python path:</span>
+	  <span class="docgrok-pathvalue" 
+		tal:content="context/path">path.in.python</span>
+	  <div class="docgrok-annotation2">
+	    Use <span class="docgrok-pycode1">from <span tal:replace="context/module_path">path</span> 
+	    import <span tal:replace="context/name">path</span></span>
+	    to use the functionality of this module in your application or component.
+	  </div>
+	</div>
+
+	<div class="docgrok-entry">
+	  <span class="docgrok-description1">Absolute file path: </span>
+	  <span class="docgrok-pathvalue" 
+		tal:content="context/getFilePath">/absolute/file/path</span>
+	  <div class="docgrok-annotation2">
+	    This is the file, wherein this class is defined.
+	  </div>
+	</div>
+
+      </div>
+      <div>
+
+	<h2>Base Classes</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getBases">
+	  class
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+	       tal:content="item/name">
+	      ClassName
+	    </a>
+	  </span>
+	  in
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:repeat="part item/path_parts"
+	       tal:attributes="href string:${view/root_url}${part/url}">
+
+	      <span tal:replace="part/name" />
+	    </a>
+	  </span>
+	  <div class="docgrok-annotation2"
+	       tal:condition="item/doc"
+	       tal:content="structure item/doc">
+	  </div>
+	  <div class="docgrok-annotation2"
+	       tal:condition="not: item/doc">
+	    Use <span class="docgrok-pycode1">from <span
+	    tal:replace="item/path">x</span> import <span
+	    tal:replace="item/name">y</span></span> to make the
+	    functionality of this class available in your application
+	    or component.
+	  </div>
+	</div>
+
+	<h2>Interfaces</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getInterfaces">
+	  interface
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+	       tal:content="item/name">
+	      ClassName
+	    </a>
+	  </span>
+	  in
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:repeat="part item/path_parts"
+	       tal:attributes="href string:${view/root_url}${part/url}">
+
+	      <span tal:replace="part/name" />
+	    </a>
+	  </span>
+	  <div class="docgrok-annotation2"
+	       tal:condition="item/doc"
+	       tal:content="structure item/doc">
+	  </div>
+	  <div class="docgrok-annotation2"
+	       tal:condition="not: item/doc">
+	    Use <span class="docgrok-pycode1">from <span
+	    tal:replace="item/path">x</span> import <span
+	    tal:replace="item/name">y</span></span> to make the
+	    functionality of this class available in your application
+	    or component.
+	  </div>
+	</div>
+
+	<div tal:repeat="iface view/getInterfaces">
+	  <div tal:content="python: str(iface)">asd</div>
+	</div>
+<!--
+	<h2>Functions:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isfunction">
+	    <div class="docgrok-pathvalue">
+	      function
+	      <a href=""
+		 tal:attributes="href 
+				 string:${view/root_url}/docgrok/${item/url}" >
+		<span tal:content="item/name">function_name</span><span tal:content="item/signature">(signature)</span>
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make the
+	      functionality of this class available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+
+	<h2>Interfaces:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isinterface">
+	    <div class="docgrok-pathvalue">
+	      interface
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+		 tal:content="item/name">
+		InterfaceName
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make this
+	      interface definition available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+
+	<h2>Classes:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isclass">
+	    <div class="docgrok-pathvalue">
+	      class
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+		 tal:content="item/name">
+		ClassName
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make the
+	      functionality of this class available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+-->
+      </div>
+
+    </div>
+  </body>
+</html>

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokgrokapplicationview.pt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/view_templates/docgrokgrokapplicationview.pt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokgrokapplicationview.pt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokgrokapplicationview.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,206 @@
+<html metal:use-macro="view/app_root/@@macros/gaia-page">
+  <head>
+    <title>DocGrok page title</title>
+  </head>
+  <body>
+    <div metal:fill-slot="content">
+
+      <h1>
+	Class
+	<span class="docgrok-pathvalue">
+	  <span class="docgrok-elemname1">
+	    <span tal:replace="context/name">ClassName</span>
+	  </span>
+	</span> in <span class="docgrok-pathvalue">
+	  <span tal:repeat="part python: view.getPathParts()[:-1]"><a href=""
+	       tal:attributes="href string:${view/root_url}${part/url}"
+	       tal:content="part/name">part</a></span></span> (a Grok Application)
+      </h1>
+      <div class="docgrok-entry" 
+	   tal:content="structure python: view.getDoc(context.getDocString())">
+	Documentation string.
+      </div>
+      <div>
+	<h2>Paths</h2>
+
+	<div class="docgrok-entry">
+	  <span class="docgrok-description1">Python path:</span>
+	  <span class="docgrok-pathvalue" 
+		tal:content="context/path">path.in.python</span>
+	  <div class="docgrok-annotation2">
+	    Use <span class="docgrok-pycode1">from <span tal:replace="context/module_path">path</span> 
+	    import <span tal:replace="context/name">path</span></span>
+	    to use the functionality of this module in your application or component.
+	  </div>
+	</div>
+
+	<div class="docgrok-entry">
+	  <span class="docgrok-description1">Absolute file path: </span>
+	  <span class="docgrok-pathvalue" 
+		tal:content="context/getFilePath">/absolute/file/path</span>
+	  <div class="docgrok-annotation2">
+	    This is the file, wherein this class is defined.
+	  </div>
+	</div>
+
+      </div>
+      <div>
+
+	<h2>Base Classes</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getBases">
+	  class
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+	       tal:content="item/name">
+	      ClassName
+	    </a>
+	  </span>
+	  in
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:repeat="part item/path_parts"
+	       tal:attributes="href string:${view/root_url}${part/url}">
+
+	      <span tal:replace="part/name" />
+	    </a>
+	  </span>
+	  <div class="docgrok-annotation2"
+	       tal:condition="item/doc"
+	       tal:content="structure item/doc">
+	  </div>
+	  <div class="docgrok-annotation2"
+	       tal:condition="not: item/doc">
+	    Use <span class="docgrok-pycode1">from <span
+	    tal:replace="item/path">x</span> import <span
+	    tal:replace="item/name">y</span></span> to make the
+	    functionality of this class available in your application
+	    or component.
+	  </div>
+	</div>
+
+	<h2>Interfaces</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getInterfaces">
+	  interface
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+	       tal:content="item/name">
+	      ClassName
+	    </a>
+	  </span>
+	  in
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:repeat="part item/path_parts"
+	       tal:attributes="href string:${view/root_url}${part/url}">
+
+	      <span tal:replace="part/name" />
+	    </a>
+	  </span>
+	  <div class="docgrok-annotation2"
+	       tal:condition="item/doc"
+	       tal:content="structure item/doc">
+	  </div>
+	  <div class="docgrok-annotation2"
+	       tal:condition="not: item/doc">
+	    Use <span class="docgrok-pycode1">from <span
+	    tal:replace="item/path">x</span> import <span
+	    tal:replace="item/name">y</span></span> to make the
+	    functionality of this class available in your application
+	    or component.
+	  </div>
+	</div>
+
+	<div tal:repeat="iface view/getInterfaces">
+	  <div tal:content="python: str(iface)">asd</div>
+	</div>
+<!--
+	<h2>Functions:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isfunction">
+	    <div class="docgrok-pathvalue">
+	      function
+	      <a href=""
+		 tal:attributes="href 
+				 string:${view/root_url}/docgrok/${item/url}" >
+		<span tal:content="item/name">function_name</span><span tal:content="item/signature">(signature)</span>
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make the
+	      functionality of this class available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+
+	<h2>Interfaces:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isinterface">
+	    <div class="docgrok-pathvalue">
+	      interface
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+		 tal:content="item/name">
+		InterfaceName
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make this
+	      interface definition available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+
+	<h2>Classes:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isclass">
+	    <div class="docgrok-pathvalue">
+	      class
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+		 tal:content="item/name">
+		ClassName
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make the
+	      functionality of this class available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+-->
+      </div>
+
+    </div>
+  </body>
+</html>

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokinterfaceview.pt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/view_templates/docgrokinterfaceview.pt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokinterfaceview.pt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokinterfaceview.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,206 @@
+<html metal:use-macro="view/app_root/@@macros/gaia-page">
+  <head>
+    <title>DocGrok page title</title>
+  </head>
+  <body>
+    <div metal:fill-slot="content">
+
+      <h1>
+	Interface
+	<span class="docgrok-pathvalue">
+	  <span class="docgrok-elemname1">
+	    <span tal:replace="context/name">ClassName</span>
+	  </span>
+	</span> in <span class="docgrok-pathvalue">
+	  <span tal:repeat="part python: view.getPathParts()[:-1]"><a href=""
+	       tal:attributes="href string:${view/root_url}${part/url}"
+	       tal:content="part/name">part</a></span></span> (Python Class)
+      </h1>
+      <div class="docgrok-entry" 
+	   tal:content="structure python: view.getDoc(context.getDocString())">
+	Documentation string.
+      </div>
+      <div>
+	<h2>Paths</h2>
+
+	<div class="docgrok-entry">
+	  <span class="docgrok-description1">Python path:</span>
+	  <span class="docgrok-pathvalue" 
+		tal:content="context/path">path.in.python</span>
+	  <div class="docgrok-annotation2">
+	    Use <span class="docgrok-pycode1">from <span tal:replace="context/module_path">path</span> 
+	    import <span tal:replace="context/name">path</span></span>
+	    to use the functionality of this module in your application or component.
+	  </div>
+	</div>
+
+	<div class="docgrok-entry">
+	  <span class="docgrok-description1">Absolute file path: </span>
+	  <span class="docgrok-pathvalue" 
+		tal:content="context/getFilePath">/absolute/file/path</span>
+	  <div class="docgrok-annotation2">
+	    This is the file, wherein this class is defined.
+	  </div>
+	</div>
+
+      </div>
+      <div>
+
+	<h2>Base Classes</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getBases">
+	  class
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+	       tal:content="item/name">
+	      ClassName
+	    </a>
+	  </span>
+	  in
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:repeat="part item/path_parts"
+	       tal:attributes="href string:${view/root_url}${part/url}">
+
+	      <span tal:replace="part/name" />
+	    </a>
+	  </span>
+	  <div class="docgrok-annotation2"
+	       tal:condition="item/doc"
+	       tal:content="structure item/doc">
+	  </div>
+	  <div class="docgrok-annotation2"
+	       tal:condition="not: item/doc">
+	    Use <span class="docgrok-pycode1">from <span
+	    tal:replace="item/path">x</span> import <span
+	    tal:replace="item/name">y</span></span> to make the
+	    functionality of this class available in your application
+	    or component.
+	  </div>
+	</div>
+
+	<h2>Interfaces</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getInterfaces">
+	  interface
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+	       tal:content="item/name">
+	      ClassName
+	    </a>
+	  </span>
+	  in
+	  <span class="docgrok-pathvalue">
+	    <a href=""
+	       tal:repeat="part item/path_parts"
+	       tal:attributes="href string:${view/root_url}${part/url}">
+
+	      <span tal:replace="part/name" />
+	    </a>
+	  </span>
+	  <div class="docgrok-annotation2"
+	       tal:condition="item/doc"
+	       tal:content="structure item/doc">
+	  </div>
+	  <div class="docgrok-annotation2"
+	       tal:condition="not: item/doc">
+	    Use <span class="docgrok-pycode1">from <span
+	    tal:replace="item/path">x</span> import <span
+	    tal:replace="item/name">y</span></span> to make the
+	    functionality of this class available in your application
+	    or component.
+	  </div>
+	</div>
+
+	<div tal:repeat="iface view/getInterfaces">
+	  <div tal:content="python: str(iface)">asd</div>
+	</div>
+<!--
+	<h2>Functions:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isfunction">
+	    <div class="docgrok-pathvalue">
+	      function
+	      <a href=""
+		 tal:attributes="href 
+				 string:${view/root_url}/docgrok/${item/url}" >
+		<span tal:content="item/name">function_name</span><span tal:content="item/signature">(signature)</span>
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make the
+	      functionality of this class available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+
+	<h2>Interfaces:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isinterface">
+	    <div class="docgrok-pathvalue">
+	      interface
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+		 tal:content="item/name">
+		InterfaceName
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make this
+	      interface definition available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+
+	<h2>Classes:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isclass">
+	    <div class="docgrok-pathvalue">
+	      class
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+		 tal:content="item/name">
+		ClassName
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make the
+	      functionality of this class available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+-->
+      </div>
+
+    </div>
+  </body>
+</html>

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokmoduleview.pt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/view_templates/docgrokmoduleview.pt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokmoduleview.pt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokmoduleview.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,129 @@
+<html metal:use-macro="view/app_root/@@macros/gaia-page">
+  <head>
+    <title>DocGrok page title</title>
+  </head>
+  <body>
+    <div metal:fill-slot="content">
+
+      <h1>
+	<span class="docgrok-pathvalue">
+	  <span tal:repeat="part view/getPathParts"><a href=""
+	       tal:attributes="href string:${view/root_url}${part/url}"
+	       tal:content="part/name">part</a></span></span> (Python Module)
+      </h1>
+      <div class="docgrok-entry" 
+	   tal:content="structure python: view.getDoc(context.getDocString())">
+	Documentation string.
+      </div>
+      <div>
+	<h2>Paths</h2>
+
+	<div class="docgrok-entry">
+	  <span class="docgrok-description1">Python path:</span>
+	  <span class="docgrok-pathvalue" 
+		tal:content="context/path">path.in.python</span>
+	  <div class="docgrok-annotation2">
+	    Use <span class="docgrok-pycode1">import 
+	    <span tal:replace="context/path">path</span></span>
+	    to use the functionality of this module in your application or component.
+	  </div>
+	</div>
+
+	<div class="docgrok-entry">
+	  <span class="docgrok-description1">Absolute file path: </span>
+	  <span class="docgrok-pathvalue" 
+		tal:content="context/getFilePath">/absolute/file/path</span>
+	  <div class="docgrok-annotation2">
+	    This is the file, where this module is located in file system.
+	  </div>
+	</div>
+
+      </div>
+      <div>
+
+	<h2>Functions:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isfunction">
+	    <div class="docgrok-pathvalue">
+	      function
+	      <a href=""
+		 tal:attributes="href 
+				 string:${view/root_url}/docgrok/${item/url}" >
+		<span tal:content="item/name">function_name</span><span tal:content="item/signature">(signature)</span>
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make the
+	      functionality of this class available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+
+	<h2>Interfaces:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isinterface">
+	    <div class="docgrok-pathvalue">
+	      interface
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+		 tal:content="item/name">
+		InterfaceName
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make this
+	      interface definition available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+
+	<h2>Classes:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/isclass">
+	    <div class="docgrok-pathvalue">
+	      class
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+		 tal:content="item/name">
+		ClassName
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      Use <span class="docgrok-pycode1">from <span
+	      tal:replace="context/path">x</span> import <span
+	      tal:replace="item/name">y</span></span> to make the
+	      functionality of this class available in your application
+	      or component.
+	    </div>
+	  </div>
+	</div>
+
+      </div>
+
+    </div>
+  </body>
+</html>

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokpackageview.pt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/view_templates/docgrokpackageview.pt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokpackageview.pt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokpackageview.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,130 @@
+<html metal:use-macro="view/app_root/@@macros/gaia-page">
+  <head>
+    <title>DocGrokPackage page title</title>
+  </head>
+  <body>
+    <div metal:fill-slot="content">
+
+      <h1>
+	<span class="docgrok-pathvalue">
+	  <span tal:repeat="part view/getPathParts"><a href=""
+						       tal:attributes="href string:${view/root_url}${part/url}"
+						       tal:content="part/name">part</a></span>
+	</span> 
+	(Python Package)
+      </h1>
+      <div>
+
+	<h2>Paths</h2>
+
+	<div class="docgrok-entry">
+	  <span class="docgrok-description1">Python path:</span>
+	  <span class="docgrok-pathvalue" 
+		tal:content="context/path">path.in.python</span>
+	  <div class="docgrok-annotation2">
+	    Use <span class="docgrok-pycode1">import 
+	    <span tal:replace="context/path">path</span></span>
+	    to use the functionality of this package in your application or component.
+	  </div>
+	</div>
+
+	<div class="docgrok-entry">
+	  <span class="docgrok-description1">Absolute file path: </span>
+	  <span class="docgrok-pathvalue" 
+		tal:content="context/getFilePath">absolute/file/path</span>
+	  <div class="docgrok-annotation2">
+	    This is, where this package is located in file system.
+	  </div>
+	</div>
+
+	<h2>Subpackages:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/ispackage">
+	    <div class="docgrok-pathvalue">
+	      package
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+		 tal:content="string: ${context/path}.${item/name}">
+		moduleName
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      You can use <span class="docgrok-pycode1">import <span
+	      tal:replace="string: ${context/path}.${item/name}">a.b</span>
+	    </span>
+	    to make the elements of this package available in your 
+	    application or component.
+	    </div>
+	  </div>
+	</div>
+
+	<h2>Modules:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/ismodule">
+	    <div class="docgrok-pathvalue">
+	      module
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+		 tal:content="string: ${context/path}.${item/name}">
+		moduleName
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+	      You can use <span class="docgrok-pycode1">import <span
+	      tal:replace="string: ${context/path}.${item/name}">a.b</span>
+	    </span>
+	    to make the elements of this module available in your 
+	    application or component.
+	    </div>
+	  </div>
+	</div>
+
+	<h2>Textfiles:</h2>
+
+	<div class="docgrok-entry" tal:repeat="item view/getEntries">
+	  <div tal:condition="item/istextfile">
+	    <div class="docgrok-pathvalue">
+	      
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/${item/url}" 
+		 tal:content="string: ${item/name}">
+		moduleName
+	      </a>
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="item/doc"
+		 tal:content="structure item/doc">
+	    </div>
+	    <div class="docgrok-annotation2"
+		 tal:condition="not: item/doc">
+<!--
+	      You can use <span class="docgrok-pycode1">import <span
+	      tal:replace="string: ${context/path}.${item/name}">a.b</span>
+	    </span>
+	    to make the elements of this package available in your 
+	    application or component.
+-->
+	    </div>
+	  </div>
+	</div>
+
+<!--
+	<div tal:content="context/msg" />
+-->
+
+      </div>
+    </div>
+  </body>
+</html>

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgroktextfileview.pt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/view_templates/docgroktextfileview.pt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgroktextfileview.pt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgroktextfileview.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,40 @@
+<html metal:use-macro="view/app_root/@@macros/gaia-page">
+  <head>
+    <title>DocGrok page title</title>
+  </head>
+  <body>
+    <div metal:fill-slot="content">
+
+      <div class="docgrok-sourceheader">
+	<h1>
+	  <span class="docgrok-pathvalue"
+		tal:content="view/context/filename">
+	    filename.txt
+	  </span>
+	  (Text file in
+	  <span class="docgrok-pathvalue">
+	    <span tal:repeat="part view/getPackagePathParts"><a href=""
+							 tal:attributes="href string:${view/root_url}${part/url}"
+							 tal:content="part/name">part</a></span>
+	  </span>) 
+	</h1>
+	<div class="docgrok-entry">
+	  <span class="docgrok-description1">File path:</span>
+
+	  <span class="docgrok-pathvalue"
+		tal:content="view/context/getFilePath"
+		>
+	    /home/uli/blah...
+	  </span>
+	  <div class="docgrok-annotation1">
+	    This is, where this text file can be found.
+	  </div>
+	</div>
+      </div>
+      <div class="docgrok-sourcetext" 
+	   tal:content="structure view/getContent">
+      </div>
+    </div>
+    <div metal:fill-slot="footer"></div>
+  </body>
+</html>

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokview.pt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/view_templates/docgrokview.pt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokview.pt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/docgrokview.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,51 @@
+<html metal:use-macro="view/app_root/@@macros/gaia-page">
+  <head>
+    <title>DocGrok page title</title>
+  </head>
+  <body>
+    <div metal:fill-slot="content">
+      <div tal:condition="not:view/getPathParts"> 
+	<h1 >
+	  Welcome to DocGrok...
+	</h1>
+	<div>
+	  you might want to discover the following trails...
+	  <ul>
+	    <li>
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/zope">
+	      The zope package</a>
+	    </li>
+	    <li>
+	      <a href=""
+		 tal:attributes="href string:${view/root_url}/docgrok/grok">
+	      The Grok package</a>
+	    </li>
+	  </ul>
+	</div>
+      </div>
+
+      <div tal:condition="view/getPathParts">
+	<h1>
+
+	  DocGrok Documentation for
+	  <span class="docgrok-pathvalue">
+	    <span tal:repeat="part view/getPathParts"><a href=""
+							 tal:attributes="href string:${view/root_url}${part/url}"
+							 tal:content="part/name">part</a></span>
+	  </span> 
+	</h1>
+	<div class="Content">
+	  <h2>Path</h2>
+	  <div tal:content="context/path">
+	    path.to.some.element
+	  </div>
+	  <div class="description1">
+	    The python path of this element.
+	  </div>
+	</div>
+      </div>
+    </div>
+    <div metal:fill-slot="footer">asda</div>
+  </body>
+</html>

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/gaiaview.pt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/view_templates/gaiaview.pt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/gaiaview.pt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/gaiaview.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1 @@
+<!-- Just a placeholder -->

Modified: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/index.pt
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/index.pt	2007-07-12 13:55:41 UTC (rev 77741)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/index.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -1,50 +1,14 @@
-<html>
-  <head>
-    <title>grok administration interface</title>
-  </head>
-
-  <body tal:define="apps context/values">
-    <h1>Grok Applications</h1>
-
-    <form tal:attributes="action string:${context/@@absolute_url}/delete"
-          tal:condition="apps|nothing">
-      <fieldset>
-        <legend>Installed applications</legend>
-
-    <ul>
-      <li tal:repeat="app apps">
-        <input type="checkbox" tal:attributes="value app/__name__;
-                                               name string:items" />
-        <a tal:attributes="href string:${context/@@absolute_url}/${app/__name__}">
-          <span tal:replace="app/__name__"/>
-          (<span tal:replace="app/__class__/__name__"/>)
-        </a>
-      </li>
-    </ul>
-
-        <p><input type="submit" value="Delete Selected"/></p>
-        </fieldset>
-    </form>
-    <form tal:attributes="action string:${context/@@absolute_url}/add">
-      <fieldset>
-        <legend>Add application</legend>
-
-        <p>
-          <label>Application: 
-            <select height="1" name="application"> 
-              <option tal:repeat="app view/applications" 
-                tal:attributes="value app" 
-                tal:content="app"
-                />
-            </select> 
-          </label>
-        </p>
-
-        <p><label>Name: <input type="text" name="name"/></label></p>
-
-        <p><input type="submit" value="Add"/></p>
-
-      </fieldset>
-    </form>
-  </body>
+<html metal:use-macro="context/@@macros/gaia-page">
+  <div metal:fill-slot="content">
+    <h1></h1>
+    <div class="logo">
+      <a href="context/@@appsindex"
+	 tal:attributes="href string:${context/@@absolute_url}/appsindex">
+	<img alt="Image of Grok relaxing..."
+	     src="grok-relax.jpg"
+	     tal:attributes="src view/static/grok-relax.png" />
+      </a>
+    </div>
+  </div>
+  <div metal:fill-slot="footer">asda</div>
 </html>

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/macros.pt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/view_templates/macros.pt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/macros.pt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/macros.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,92 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+  metal:define-macro="gaia-page">
+  <head>
+    <title
+      metal:define-slot="title"
+      >grok administration interface</title>
+    <link metal:define-slot="header"
+      rel="stylesheet" type="text/css" href="static/grok.css"
+      tal:attributes="href view/static/grok.css" />
+    <metal:block define-slot="extrahead">
+    </metal:block>
+  </head>
+
+  <body>
+    <div>
+      <div id="Banner">
+        <a href="/" id="logo">
+          <img alt="Grok" src="images/grok-admin.jpg"
+            tal:attributes="src view/static/grok-admin.jpg" />
+        </a>
+      </div>
+      <div id="Breadcrumbs">
+        <div id="Banner-Shadow">
+          &nbsp;
+        </div>
+      </div>
+      <div id="Fireplace">
+        <img alt="Fire" src="images/Fire.gif"
+          tal:attributes="src view/static/grok-relax5.png" />
+      </div>
+      <p></p>
+      <center tal:define="currview python:view.url()">
+        <span class="menu_link_inactive"
+          tal:define="target string:${view/root_url}/appsindex">
+          <a href="appsindex"
+            tal:condition="python: target != currview"
+            tal:attributes="href target"
+            >Applications</a>
+          <span class="emph"
+            tal:condition="python: target == currview">
+            Applications
+          </span>
+        </span>
+        &nbsp;&nbsp;
+        <!--<span class="menu_link_inactive"
+          tal:define="target python:view.root_url('z3index')"> -->
+          <!-- <span class="menu_link_inactive"
+            tal:define="target python:view.context.url('z3index')"> -->
+            <span class="menu_link_inactive"
+              tal:define="target string:${view/root_url}/z3index"
+              talasd:define="target string:${view/context/@@absolute_url}/z3index"
+              >
+              <a href="z3index"
+                tal:condition="python: target != currview"
+                tal:attributes="href target"
+                >Server Control</a>
+              <span class="emph"
+                tal:condition="python: target == currview">
+                Server Control
+              </span>
+            </span>
+            &nbsp;&nbsp;
+            <a href=""
+              tal:attributes="href view/root_url">Debug</a>
+            &nbsp;&nbsp;
+            <a href=""
+              tal:attributes="href string:${view/root_url}/docgrok/">
+              <span tal:attributes="class python:view.in_docgrok() and 'emph'" 
+                >Documentation</span>
+            </a>
+          </center>
+
+          <center>
+            <div id="Content">
+              <div metal:define-slot="content">
+
+                <h1>Welcome to Grok!</h1>
+
+                <div>
+                  Your friendly and easy way to Zope 3.
+                </div>
+
+              </div>
+              <div>
+                <p id="Footer-copyright">&copy; Copyright 2007, The Zope Foundation<br />Design inspired by Sebastian Ware</p>
+              </div>
+            </div>
+          </center>
+
+
+        </body>
+      </html>

Copied: Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/z3index.pt (from rev 77741, Sandbox/ulif/grok-adminui-mergeprepare/src/grok/admin/view_templates/z3index.pt)
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/z3index.pt	                        (rev 0)
+++ Sandbox/ulif/grok-adminui/src/grok/admin/view_templates/z3index.pt	2007-07-12 14:07:50 UTC (rev 77742)
@@ -0,0 +1,60 @@
+<html metal:use-macro="context/@@macros/gaia-page">
+  <div metal:fill-slot="content">
+    <h1>Manage your Zope 3 instance:</h1>
+
+    <form method="POST" action=""
+	  tal:attributes="action string:${context/@@absolute_url}/z3index">
+      <fieldset>
+	<legend>Manage Server Process</legend>
+	<input type="submit" name="restart" class="button" value="Restart Zope 3" />
+	<input type="submit" name="shutdown" class="button" value="Stop Zope 3" />
+	after <input type="text" name="time" value="0" size="4" /> seconds
+       </fieldset>
+
+      <fieldset tal:define="ri view/ri">
+	<legend>Server Process Info</legend>
+	<div>
+	  <span class="emph">Uptime:</span>
+	  <span tal:content="ri/Uptime">unknown</span> 
+	</div>
+	<div>
+	  <span class="emph">System Platform:</span>
+	  <span tal:content="ri/SystemPlatform">unknown</span> 
+	</div>
+	<div>
+	  <span class="emph">Zope Version:</span>
+	  <span tal:content="ri/ZopeVersion">unknown</span> 
+	</div>
+	<div>
+	  <span class="emph">Python Version:</span>
+	  <span tal:content="ri/PythonVersion">unknown</span> 
+	</div>
+	<div>
+	  <span class="emph">Command Line:</span>
+	  <span tal:content="ri/CommandLine">unknown</span> 
+	</div>
+	<div>
+	  <span class="emph">Preferred Encoding:</span>
+	  <span tal:content="ri/PreferredEncoding">unknown</span> 
+	</div>
+	<div>
+	  <span class="emph">File System Encoding:</span>
+	  <span tal:content="ri/FileSystemEncoding">unknown</span> 
+	</div>
+	<div>
+	  <span class="emph">Process Id:</span>
+	  <span tal:content="ri/ProcessId">unknown</span> 
+	</div>
+	<div>
+	  <span class="emph">Python Path:</span>
+	  <div tal:repeat="path ri/PythonPath">
+	    <span tal:content="path">unknown</span> 
+	  </div>
+	</div>
+       </fieldset>
+
+    </form>
+
+  </div>
+
+</html>

Modified: Sandbox/ulif/grok-adminui/src/grok/ftests/admin/admin.py
===================================================================
--- Sandbox/ulif/grok-adminui/src/grok/ftests/admin/admin.py	2007-07-12 13:55:41 UTC (rev 77741)
+++ Sandbox/ulif/grok-adminui/src/grok/ftests/admin/admin.py	2007-07-12 14:07:50 UTC (rev 77742)
@@ -2,47 +2,60 @@
   >>> import grok
   >>> grok.grok('grok.ftests.admin.admin')
 
+We fetch the standard page
+
   >>> from zope.testbrowser.testing import Browser
   >>> browser = Browser()
   >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
   >>> browser.handleErrors = False
   >>> browser.open("http://localhost/")
   >>> print browser.contents
-  <html>
+  <html xmlns="http://www.w3.org/1999/xhtml">
   ...
-  ...<legend>Add application</legend>
+  ...      <legend>Add application</legend>
   ...
-  >>> browser.getControl('Application').displayValue = ['grok.ftests.admin.admin.MammothManager']
-  >>> browser.getControl('Name').value = 'my-mammoth-manager'
-  >>> browser.getControl('Add').click()
+
+  >>> browser.getControl('Name your new app:',index=12).value = 'my-mammoth-manager'
+
+We are able to add a mammoth manager...
+
+  >>> browser.getControl('Create',index=12).click()
+
   >>> print browser.contents
-  <html>
+  <html xmlns="http://www.w3.org/1999/xhtml">
   ...
-      <li>
-        <input type="checkbox" name="items" value="my-mammoth-manager" />
-        <a href="http://localhost/my-mammoth-manager">
-          my-mammoth-manager
-          (MammothManager)
+  ... <legend>Installed applications</legend>
+  ... <input type="checkbox" class="checkbox" name="items"
+             value="my-mammoth-manager" />
+      <a href="http://localhost/my-mammoth-manager">
+           my-mammoth-manager
+           (MammothManager)
         </a>
-      </li>
+  ... <legend>Add application</legend>
   ...
-  >>> browser.getLink('my-mammoth-manager').click()
+
+Launch the added mammoth manager
+
+  >>> mylink = browser.getLink('my-mammoth-manager (MammothManager)').click()
   >>> print browser.contents
   Let's manage some mammoths!
 
-We are able to delete installed applications.
+  >>> print browser.url
+  http://localhost/my-mammoth-manager
 
+We are able to delete installed mammoth-mnagers
+
   >>> browser.open("http://localhost/")
   >>> print browser.contents
-  <html>
+  <html xmlns="http://www.w3.org/1999/xhtml">
   ...
-  ...<legend>Installed applications</legend>
+  ... <legend>Installed applications</legend>
   ...
   >>> ctrl = browser.getControl(name='items')
   >>> ctrl.getControl(value='my-mammoth-manager').selected = True
   >>> browser.getControl('Delete Selected').click()
   >>> print browser.contents
-  <html>
+  <html xmlns="http://www.w3.org/1999/xhtml">
   ...
   ...<legend>Add application</legend>
   ...
@@ -51,6 +64,7 @@
 import grok
 
 class MammothManager(grok.Application, grok.Container):
+    """"A mammoth manager"""
     pass
 
 class Index(grok.View):



More information about the Checkins mailing list