merge branch master

This commit is contained in:
Helmut Merz 2012-07-10 09:08:25 +02:00
commit 0aa539e8f8
8 changed files with 162 additions and 47 deletions

View file

@ -483,6 +483,7 @@ class NodeView(BaseView):
def virtualTarget(self):
tv = self.viewAnnotations.get('targetView')
if tv is not None:
tv.setupController()
return tv
setup = self.setupTarget
return self.getViewForTarget(self.virtualTargetObject, setup=setup)

View file

@ -2,21 +2,73 @@
<div metal:define-macro="main">
<div tal:attributes="class string:content-$level;">
<div tal:define="report item/reportInstance;
reportView nocall:item"
tal:attributes="class string:content-$level;">
<metal:block use-macro="view/concept_macros/concepttitle" />
<form method="post" name="report_data" action="results.html">
<tal:hidden define="params item/dynamicParams">
<form method="post" name="report_data">
<tal:hidden define="params item/dynamicParams"
tal:condition="nothing">
<input type="hidden"
tal:repeat="name params"
tal:attributes="name name;
value params/?name" /></tal:hidden>
<div metal:use-macro="item/report_macros/params" />
<div metal:define-macro="buttons">
<input type="submit" name="report_execute" value="Execute Report"
i18n:attributes="value" />
</div>
</form>
<div metal:use-macro="item/resultsRenderer" />
</div>
</div>
<metal:block define-macro="params">
<metal:block use-macro="item/report_macros/query" />
</metal:block>
<metal:block define-macro="query"
tal:define="criteria
item/reportInstance/queryCriteria/parts|nothing">
<table>
<tr tal:repeat="field item/queryFields">
<tal:field define="fieldType field/fieldType;
crit python:criteria and criteria.get(field.name)">
<td><b><span tal:content="field/title" />: </b></td>
<td><metal:field use-macro="item/report_macros/?fieldType" /></td>
</tal:field>
</tr>
</table>
<br />
</metal:block>
<metal:field define-macro="textline">
<input tal:attributes="name string:${field/name};
value crit/comparisonValue|nothing" />
</metal:field>
<metal:field define-macro="number">
<input tal:attributes="name string:query.field.${field/name};
value crit/comparisonValue|nothing" />
</metal:field>
<metal:field define-macro="date">
<input dojoType="dijit.form.DateTextBox" style="width: 8em"
constraints="{datePattern: 'd.M.y',
min: '1980-01-01', max: '2020-12-31'}"
tal:attributes="name string:${field/name};
value crit/comparisonValue|nothing" />
</metal:field>
<metal:field define-macro="selection">
<metal:use use-macro="item/report_macros/textline" />
</metal:field>
</html>

View file

@ -134,7 +134,7 @@ class ResultsView(NodeView):
class ResultsConceptView(ConceptView):
""" View on a concept using a report.
""" View on a concept using the results of a report.
"""
reportName = None # define in subclass if applicable
@ -170,12 +170,11 @@ class ResultsConceptView(ConceptView):
reportType = self.reportType or self.report.reportType
ri = component.getAdapter(self.report, IReportInstance,
name=reportType)
#ri.view = self.nodeView
ri.view = self
return ri
def results(self):
return self.reportInstance.getResults(dict(tasks=util.getUidForObject(self.context)))
return self.reportInstance.getResults()
@Lazy
def displayedColumns(self):
@ -183,3 +182,24 @@ class ResultsConceptView(ConceptView):
def getColumnRenderer(self, col):
return self.result_macros[col.renderer]
class ReportConceptView(ResultsConceptView, ReportView):
""" View on a concept using a report.
"""
def setupController(self):
super(ReportConceptView, self).setupController()
self.registerDojoDateWidget()
@Lazy
def macro(self):
return self.report_macros['main']
@Lazy
def queryFields(self):
ri = self.reportInstance
qf = ri.getAllQueryFields()
if ri.userSettings:
return [f for f in qf if f in ri.userSettings]
return qf

View file

@ -35,7 +35,8 @@
i18n:translate="" />
</tr>
<tr tal:repeat="row results">
<td tal:repeat="col results/displayedColumns">
<td tal:repeat="col results/displayedColumns"
tal:attributes="class col/cssClass">
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</td>

View file

@ -25,7 +25,8 @@ from zope import component
from zope.i18n.locales import locales
from zope.schema.interfaces import IVocabularyFactory, IContextSourceBinder
from cybertools.composer.report.field import Field, TableCellStyle
from cybertools.composer.report.field import Field as BaseField
from cybertools.composer.report.field import TableCellStyle
from cybertools.composer.report.result import ResultSet
from cybertools.util.date import timeStamp2Date
from loops.common import baseObject
@ -33,6 +34,12 @@ from loops.expert.report import ReportInstance
from loops import util
class Field(BaseField):
def getSelectValue(self, row):
return self.getRawValue(row)
class TextField(Field):
format = 'text/restructured'

View file

@ -212,25 +212,23 @@ The executable report is a report instance that is an adapter to the
... provides=IReportInstance,
... name='work_report')
The user interface to the report is a report view, the results are presented
in a results view.
The user interface is a ReportConceptView subclass that is directly associated with the task.
>>> from loops.view import Node
>>> reportNode = addAndConfigureObject(home, Node, 'report',
... title=u'Report', target=workStatement)
>>> from loops.expert.browser.report import ReportView, ResultsView
>>> resultsView = ResultsView(reportNode, TestRequest())
>>> from loops.organize.work.report import WorkStatementView
>>> reportView = WorkStatementView(task01, TestRequest())
>>> reportView.nodeView = nodeView
>>> results = resultsView.results()#.getResult()
>>> results = reportView.results()
>>> len(list(results))
1
>>> for row in results:
... for col in resultsView.displayedColumns:
... for col in reportView.displayedColumns:
... print col.getDisplayValue(row),
... print
08/12/28 19:00 20:15
{'url': '.../home/report/.36', 'title': u'loops Development'}
{'url': '.../home/report/.33', 'title': u'john'} 01:15 00:15 finished
{'url': '.../home/.36', 'title': u'loops Development'}
{'url': '.../home/.33', 'title': u'john'} 01:15 00:15 finished
>>> results.totals.data
{'effort': 900}
@ -266,18 +264,17 @@ report is available.
... reportType='meeting_minutes')
>>> meetingMinutes.assignChild(tEvent, hasReport)
We can now access the report using a results view.
We can now access the report using a corresponding report-based view.
>>> from loops.util import getUidForObject
>>> input = dict(tasks=getUidForObject(ev01))
>>> resultsView = ResultsView(home, TestRequest(form=input))
>>> resultsView.virtualTargetObject = meetingMinutes
>>> from loops.organize.work.meeting import MeetingMinutes
>>> reportView = MeetingMinutes(ev01, TestRequest())
>>> reportView.nodeView = nodeView
>>> results = resultsView.results()
>>> results = reportView.results()
>>> len(list(results))
1
>>> for row in results:
... for col in resultsView.displayedColumns:
... for col in reportView.displayedColumns:
... print col.getDisplayValue(row),
... print
{'url': 'http://127.0.0.1/loops/views/home/.36', 'title': u'loops Development'}

View file

@ -75,8 +75,9 @@
<!-- reporting -->
<zope:adapter factory="loops.organize.work.report.WorkReportInstance"
<zope:adapter
name="work_report"
factory="loops.organize.work.report.WorkReportInstance"
provides="loops.expert.report.IReportInstance"
trusted="True" />
<zope:class class="loops.organize.work.report.WorkReportInstance">
@ -86,8 +87,15 @@
set_schema="loops.expert.report.IReportInstance" />
</zope:class>
<zope:adapter factory="loops.organize.work.report.MeetingMinutes"
<browser:page
name="work.html"
for="loops.organize.interfaces.ITask"
class="loops.organize.work.report.WorkStatementView"
permission="zope.View" />
<zope:adapter
name="meeting_minutes"
factory="loops.organize.work.report.MeetingMinutes"
provides="loops.expert.report.IReportInstance"
trusted="True" />
<zope:class class="loops.organize.work.report.MeetingMinutes">

View file

@ -26,20 +26,32 @@ from zope.component import adapter
from cybertools.composer.report.base import Report
from cybertools.composer.report.base import LeafQueryCriteria, CompoundQueryCriteria
from cybertools.composer.report.field import Field, CalculatedField
from cybertools.composer.report.field import CalculatedField
from cybertools.composer.report.result import ResultSet, Row as BaseRow
from cybertools.organize.interfaces import IWorkItems
from cybertools.util.date import timeStamp2Date
from cybertools.util.date import timeStamp2Date, timeStamp2ISO
from cybertools.util.format import formatDate
from cybertools.util.jeep import Jeep
from loops.common import adapted, baseObject
from loops.expert.field import TargetField, DateField, TextField, UrlField
from loops.expert.browser.report import ReportConceptView
from loops.expert.field import Field, TargetField, DateField, \
TextField, UrlField
from loops.expert.field import SubReport, SubReportField
from loops.expert.report import ReportInstance
from loops import util
# reporting views
class WorkStatementView(ReportConceptView):
reportName = 'work_statement'
# fields
class StateField(Field):
def getDisplayValue(self, row):
value = self.getValue(row)
return util._(value)
@ -47,9 +59,10 @@ class StateField(Field):
class TrackDateField(Field):
fieldType = 'date'
part = 'date'
format = 'short'
renderer = 'right'
cssClass = 'right'
def getValue(self, row):
value = self.getRawValue(row)
@ -65,6 +78,12 @@ class TrackDateField(Field):
view.languageInfo.language)
return u''
def getSelectValue(self, row):
value = self.getRawValue(row)
if not value:
return ''
return timeStamp2ISO(value)[:10]
class TrackTimeField(TrackDateField):
@ -73,7 +92,7 @@ class TrackTimeField(TrackDateField):
class DurationField(Field):
renderer = 'right'
cssClass = 'right'
def getValue(self, row):
value = self.getRawValue(row)
@ -100,11 +119,15 @@ tasks = Field('tasks', u'Tasks',
# work report fields
dayFrom = Field('dayFrom', u'Start Day',
dayFrom = TrackDateField('dayFrom', u'Start Day',
description=u'The first day from which to select work.',
fieldType='date',
operator=u'gt',
executionSteps=['query'])
dayTo = Field('dayTo', u'End Day',
dayTo = TrackDateField('dayTo', u'End Day',
description=u'The last day until which to select work.',
fieldType='date',
operator=u'le',
executionSteps=['query'])
day = TrackDateField('day', u'Day',
description=u'The day the work was done.',
@ -121,6 +144,7 @@ task = TargetField('taskId', u'Task',
executionSteps=['output'])
party = TargetField('userName', u'Party',
description=u'The party (usually a person) who did the work.',
fieldType='selection',
executionSteps=['query', 'sort', 'output'])
workTitle = Field('title', u'Title',
description=u'The short description of the work.',
@ -167,7 +191,8 @@ class WorkRow(BaseRow):
value = self.getDuration(attr)
return value
attributeHandlers = dict(day=getDay, duration=getDuration, effort=getEffort)
attributeHandlers = dict(day=getDay, dayFrom=getDay, dayTo=getDay,
duration=getDuration, effort=getEffort)
class WorkReportInstance(ReportInstance):
@ -178,9 +203,11 @@ class WorkReportInstance(ReportInstance):
rowFactory = WorkRow
fields = Jeep((dayFrom, dayTo, tasks,
day, timeStart, timeEnd, task, party, workTitle, #description,
day, timeStart, timeEnd, task, party, workTitle,
#description,
duration, effort, state))
userSettings = (dayFrom, dayTo, party)
defaultOutputFields = fields
defaultSortCriteria = (day, timeStart,)
states = ('done', 'done_x', 'finished')
@ -192,12 +219,13 @@ class WorkReportInstance(ReportInstance):
crit = self.context.queryCriteria or []
if not crit and 'tasks' not in form:
f = self.fields['tasks']
tasks = baseObject(self.context).getChildren([self.hasReportPredicate])
tasks = [self.view.context]
tasks = [util.getUidForObject(task) for task in tasks]
crit = [LeafQueryCriteria(f.name, f.operator, tasks, f)]
for f in self.getAllQueryFields():
if f.name in form:
crit.append(LeafQueryCriteria(f.name, f.operator, form[f.name], f))
crit.append(
LeafQueryCriteria(f.name, f.operator, form[f.name], f))
return CompoundQueryCriteria(crit)
def selectObjects(self, parts):
@ -229,8 +257,9 @@ class WorkReportInstance(ReportInstance):
# TODO: take states from parts
kw = dict(task=util.getUidForObject(baseObject(task)),
state=self.states)
if 'userName' in parts:
kw['userName'] = parts['userName'].comparisonValue
userNameCrit = parts.get('userName')
if userNameCrit and userNameCrit.comparisonValue:
kw['userName'] = userNameCrit.comparisonValue
wi = self.workItems
return wi.query(**kw)