Index: main/waeup.kofa/trunk/src/waeup/kofa/browser/reports.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/browser/reports.py	(revision 9633)
+++ main/waeup.kofa/trunk/src/waeup/kofa/browser/reports.py	(revision 9633)
@@ -0,0 +1,104 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""Browser components for report generation.
+"""
+import grok
+from zope.component import getUtility
+from zope.location.location import located
+from waeup.kofa.interfaces import IJobManager
+from waeup.kofa.browser.layout import KofaPage
+from waeup.kofa.browser.resources import tabs
+from waeup.kofa.reports import IReport, IReportsContainer
+from waeup.kofa.reports import get_generators
+
+grok.templatedir('templates')
+
+class ReportsContainerPage(KofaPage):
+    """A view on a reports container.
+    """
+    grok.name('index')
+    grok.context(IReportsContainer)
+    grok.require('waeup.manageReports')
+
+    def _report_url(self, job_id):
+        """Get the PDF download URL of a report.
+        """
+        return self.url(self.context, '%s/pdf' % job_id)
+
+    def update(self, job_id=None, DISCARD=None, DOWNLOAD=None):
+        self.entries = []
+        user_id = self.request.principal.id
+        if job_id and DISCARD:
+            entry = self.context.report_entry_from_job_id(job_id)
+            self.context.delete_report_entry(entry)
+            self.flash('Report discarded: %s' % job_id)
+        self.entries = self.context.get_report_jobs_description(user_id)
+        if job_id and DOWNLOAD:
+            self.redirect(self._report_url(job_id))
+            return
+        return
+
+
+class ReportsContainerTraverser(grok.Traverser):
+    """A traverser for reports containers.
+    """
+    grok.context(IReportsContainer)
+    def traverse(self, name):
+        """Return a report generator or report if one is registered under
+        `name`.
+
+        Generators are registered by their utility names while reports
+        are looked up by their job id. So, `name` must be a report
+        generator name or a valid job_id of a report job.
+        """
+        generators = dict(list(get_generators()))
+        result = generators.get(name, None)
+        if result:
+            # give generator a location in URLs (make url() work)
+            return located(result, self.context, name)
+        result = self.context.report_entry_from_job_id(name)
+        if result:
+            manager = getUtility(IJobManager)
+            job = manager.get(name)
+            report = job.result
+            return located(report, self.context, name)
+        return None
+
+class ReportsContainerCreate(KofaPage):
+    """Create a new report.
+    """
+    grok.name('create')
+    grok.context(IReportsContainer)
+    grok.require('waeup.manageReports')
+
+    def update(self, START_GENERATOR=None, generator=None):
+        self.creators = self.get_creators()
+        self.generator_names = [x[1] for x in self.creators]
+        if START_GENERATOR and generator and generator in self.generator_names:
+            self.redirect(self.url(self.context, generator))
+        pass
+
+    def get_creators(self):
+        """Get all registered report generator names.
+
+        Returns a list of tuples (<TITLE>, <NAME>) with ``<TITLE>``
+        being a human readable description of the respective generator
+        and ``<NAME>`` being the registration name with the ZCA.
+        """
+        result = [(gen.title, name) for name, gen in get_generators()]
+        return result
Index: main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/reportscontainercreate.pt
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/reportscontainercreate.pt	(revision 9633)
+++ main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/reportscontainercreate.pt	(revision 9633)
@@ -0,0 +1,50 @@
+<div i18n:domain="waeup.kofa">
+  <h2 i18n:translate="">Create Report</h2>
+  <div class="row">
+    <div class="span8 columns">
+      <div class="span8 columns">
+	<p i18n:translate="">
+	  Here you can create reports representing portal data.
+	</p>
+	<p i18n:translate="">
+	  Please pick the type of report you want to create from the
+	  selection below.
+	</p>
+	<p i18n:translate="">
+	  Afterwards you can configure the report (do the settings).
+	  The report data will be calculated and then made available
+	  for you to view/download.
+	</p>
+      </div>
+      <form  method="POST">
+      <fieldset>
+
+	<div class="clearfix">
+	  <label for="generator">Report Type:</label>
+	  <div class="input">
+	    <select name="generator">
+	      <span tal:repeat="items view/creators" tal:omit-tag="">
+		<option
+		    tal:define="name python: items[1]; title python: items[0]"
+		    tal:attributes="value name">
+		  <span tal:replace="title">TITLE</span>
+		</option>
+	      </span>
+	    </select>
+	    <span class="help-inline" i18n:translate="">
+	      Type of report to create
+	    </span>
+	  </div>
+
+	</div>
+	<div class="input">
+	  <input i18n:translate="" type="submit" class="btn primary"
+		 name="START_GENERATOR" value="Configure" />
+	</div>
+
+      </fieldset>
+    </form>
+
+    </div>
+  </div>
+</div>
Index: main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/reportscontainerpage.pt
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/reportscontainerpage.pt	(revision 9633)
+++ main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/reportscontainerpage.pt	(revision 9633)
@@ -0,0 +1,41 @@
+<h2>Reports</h2>
+<div class="span12">
+  <form method="POST">
+    <a href="" class="btn primary">Reload</a>
+    <a href="create" class="btn secondary">Create new</a>
+  </form>
+</div>
+<hr />
+<div tal:repeat="entry view/entries" class="row">
+  <div class="span12">
+    <form method="POST">
+      <div class="span10">
+	<b>Report <span tal:replace="python: entry[0]">12</span>:</b>
+	<span tal:replace="python: entry[1]">Report Description</span>
+      </div>
+      <div class="span10">
+	status:
+	<b><span tal:replace="python: entry[2]">status</span></b>
+      </div>
+      <div class="span10">
+	<input type="submit" class="btn secondary"
+	       name="DISCARD" value="Discard" />
+	<input type="submit" class="btn secondary"
+	       name="DOWNLOAD" value="Download" />
+      </div>
+      <div class="span6">
+	<input type="hidden" name="job_id"
+	       tal:attributes="value python: entry[0]" />
+      </div>
+      <!-- span tal:replace="entry">ENRY</span -->
+    </form>
+    <hr />
+  </div>
+</div>
+
+<div class="span12">
+  <form method="POST">
+    <a href="" class="btn primary">Reload</a>
+    <a href="create" class="btn secondary">Create new</a>
+  </form>
+</div>
