merge branch master

This commit is contained in:
Helmut Merz 2012-05-15 16:52:55 +02:00
commit f9dca48cde
22 changed files with 349 additions and 36 deletions

View file

@ -77,6 +77,7 @@ from loops.versioning.interfaces import IVersionable
concept_macros = ViewPageTemplateFile('concept_macros.pt')
conceptMacrosTemplate = concept_macros
resource_macros = ViewPageTemplateFile('resource_macros.pt')
form_macros = ViewPageTemplateFile('form_macros.pt')
class NameField(schema.ASCIILine):
@ -161,7 +162,10 @@ class BaseView(GenericView, I18NView):
@Lazy
def resource_macros(self):
return self.controller.getTemplateMacros('resource', resource_macros)
#return resource_macros.macros
@Lazy
def form_macros(self):
return self.controller.getTemplateMacros('form', form_macros)
def breadcrumbs(self):
return []

View file

@ -45,7 +45,8 @@
values python: [v for v in data.values() if v];
fields item/fields"
tal:condition="values">
<table tal:attributes="ondblclick item/openEditWindow">
<table class="fields"
tal:attributes="ondblclick item/openEditWindow">
<tal:row repeat="field fields">
<tr tal:define="fieldName field/name;
value nocall:data/?fieldName;

View file

@ -147,6 +147,10 @@ table.records th, table.records td {
border: 1px solid black;
}
table.report td {
vertical-align: top;
}
dl.docutils dt {
font-weight: bold;
margin-top: 0.3em;
@ -422,6 +426,19 @@ img.notselected {
margin-bottom: 4px;
}
.header-1 {
font-size: 120%;
font-weight: bold;
}
.center {
text-align: center;
}
.right {
text-align: right;
}
/* comments */
div.comment {

View file

@ -27,7 +27,8 @@
<div id="content" class="span-6"
metal:define-macro="content">
<metal:breadcrumbs define-slot="breadcrumbs">
<table tal:define="crumbs view/breadcrumbs"
<table class="breadcrumbs"
tal:define="crumbs view/breadcrumbs"
tal:condition="crumbs">
<tr>
<td style="white-space: nowrap; vertical-align: top; width: 10%"

View file

@ -100,18 +100,30 @@ textarea {
font-size: 100%;
}
table {
border-collapse: collapse;
}
thead th {
background: none;
}
/* class-specific */
.breadcrumbs td {
padding-left: 0;
}
.description {
font-style: italic;
/* margin-top: 0.5em;*/
margin-bottom: 0.3em;
}
.fields td {
vertical-align: top;
}
.dialog div.heading {
font-weight: bold;
font-size: 140%;
@ -136,7 +148,6 @@ table.listing {
margin: 1px;
/*margin-top: 0.5em; */
margin-bottom: 1em;
border-collapse: collapse;
}
table.listing th {
@ -206,10 +217,6 @@ table.listing th span.descending {
background-repeat: no-repeat;
}
table.records {
border-collapse: collapse;
}
table.records input, table.records textarea {
border: none;
padding: 0;
@ -490,6 +497,11 @@ img.notselected {
margin-bottom: 4px;
}
.header-1 {
font-size: 120%;
font-weight: bold;
}
.center {
text-align: center;
}

View file

@ -166,8 +166,8 @@ class AdapterBase(object):
def uid(self):
return util.getUidForObject(self.context)
def getChildren(self):
for c in self.context.getChildren():
def getChildren(self, predicates=None):
for c in self.context.getChildren(predicates):
yield adapted(c, self.languageInfo)
def getLongTitle(self):

View file

@ -27,7 +27,9 @@ from zope.cachedescriptors.property import Lazy
from cybertools.typology.interfaces import IType
from loops.browser.lobo import standard
from loops.browser.concept import ConceptRelationView as BaseConceptRelationView
from loops.browser.concept import ConceptView
from loops.browser.concept import ConceptRelationView as \
BaseConceptRelationView
from loops.browser.resource import ResourceView as BaseResourceView
from loops.common import adapted, baseObject
@ -36,7 +38,24 @@ standard_template = standard.standard_template
book_template = ViewPageTemplateFile('view_macros.pt')
class PageLayout(standard.Layout):
class Base(object):
@Lazy
def isPartOfPredicate(self):
return self.conceptManager['ispartof']
@Lazy
def breadcrumbsParent(self):
for p in self.context.getParents([self.isPartOfPredicate]):
return self.nodeView.getViewForTarget(p)
class SectionView(Base, ConceptView):
pass
class PageLayout(Base, standard.Layout):
def getParts(self):
parts = ['headline', 'keyquestions', 'quote', 'maintext',

View file

@ -17,6 +17,14 @@
<!-- Views -->
<zope:adapter
name="section_view"
for="loops.interfaces.IConcept
loops.browser.skin.Lobo"
provides="zope.interface.Interface"
factory="loops.compound.book.browser.SectionView"
permission="zope.View" />
<zope:adapter
name="page_layout"
for="loops.interfaces.IConcept

View file

@ -7,7 +7,7 @@ type(u'book', u'Buch', viewName=u'', typeInterface=u'',
type(u'page', u'Seite', viewName=u'page_layout',
typeInterface=u'loops.compound.book.interfaces.IPage',
options=u'action.portlet:edit_concept')
type(u'section', u'Kapitel', viewName=u'', typeInterface=u'',
type(u'section', u'Kapitel', viewName=u'section_view', typeInterface=u'',
options=u'action.portlet:create_subtype,edit_concept')
concept(u'system', u'System', u'domain')

View file

@ -42,6 +42,8 @@ results_template = ViewPageTemplateFile('results.pt')
class ReportView(ConceptView):
""" A view for defining (editing) a report.
"""
@Lazy
def report_macros(self):
@ -107,3 +109,51 @@ class ResultsView(NodeView):
def getColumnRenderer(self, col):
return self.result_macros[col.renderer]
class ResultsConceptView(ConceptView):
""" View on a concept using a report.
"""
reportName = None # define in subclass if applicable
@Lazy
def result_macros(self):
return self.controller.getTemplateMacros('results', results_template)
@Lazy
def resultsRenderer(self):
return self.reportInstance.getResultsRenderer(
'results', self.result_macros)
@Lazy
def macro(self):
return self.result_macros['content']
@Lazy
def hasReportPredicate(self):
return self.conceptManager['hasreport']
@Lazy
def report(self):
if self.reportName:
return adapted(self.conceptManager[self.reportName])
type = self.context.conceptType
reports = type.getParents([self.hasReportPredicate])
return adapted(reports[0])
@Lazy
def reportInstance(self):
ri = component.getAdapter(self.report, IReportInstance,
name=self.report.reportType)
ri.view = self.nodeView
return ri
def results(self):
return self.reportInstance.getResults(dict(tasks=util.getUidForObject(self.context)))
@Lazy
def displayedColumns(self):
return self.reportInstance.getActiveOutputFields()
def getColumnRenderer(self, col):
return self.result_macros[col.renderer]

View file

@ -3,7 +3,8 @@
<div metal:define-macro="main"
tal:define="item nocall:item/virtualTarget;
report view/reportInstance">
report view/reportInstance;
reportView nocall:view">
<div tal:attributes="class string:content-$level;">
<metal:block use-macro="view/concept_macros/concepttitle" />
</div>
@ -14,9 +15,19 @@
</div>
<div metal:define-macro="content"
tal:define="report item/reportInstance;
reportView nocall:item">
<div tal:attributes="class string:content-$level;">
<metal:block use-macro="view/concept_macros/concepttitle" />
</div>
<div metal:use-macro="item/resultsRenderer" />
</div>
<div metal:define-macro="results">
<table class="report"
tal:define="results view/results">
tal:define="results reportView/results">
<tr>
<th tal:repeat="col results/displayedColumns"
tal:content="col/title"
@ -25,14 +36,16 @@
</tr>
<tr tal:repeat="row results">
<td tal:repeat="col results/displayedColumns">
<metal:column use-macro="python:view.getColumnRenderer(col)" />
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</td>
</tr>
<tr tal:define="row nocall:results/totals"
tal:condition="nocall:row">
<td tal:repeat="col results/displayedColumns"
tal:attributes="class col/cssClass">
<metal:column use-macro="python:view.getColumnRenderer(col)" />
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</td>
</tr>
</table>
@ -76,7 +89,6 @@
<div metal:define-macro="subreport">
<tal:column>
<table class="subreport"
tal:define="results python:col.getValue(row)">
<tr>
@ -86,17 +98,18 @@
</tr>
<tr tal:repeat="row results">
<td tal:repeat="col results/displayedColumns">
<metal:column use-macro="python:view.getColumnRenderer(col)" />
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</td>
</tr>
<tr tal:define="row nocall:results/totals"
tal:condition="nocall:row">
<td tal:repeat="col results/displayedColumns">
<metal:column use-macro="python:view.getColumnRenderer(col)" />
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</td>
</tr>
</table>
</tal:column>
</div>

View file

@ -60,6 +60,7 @@ class DecimalField(Field):
styleData = {'text-align':'right'}
styleData = dict(Field.style.data, **styleData)
style = TableCellStyle(**styleData)
cssClass = 'number'
def getDisplayValue(self, row):
value = self.getRawValue(row)
@ -228,6 +229,7 @@ class SubReportField(Field):
baseReport = row.parent.context
instance = self.reportFactory(baseReport.context)
instance.view = baseReport.view
instance.parentRow = row
return instance
def getValue(self, row):

View file

@ -98,7 +98,7 @@ class ReportInstance(BaseReport):
if dynaParams is not None:
for k, v in dynaParams.items():
if k in crit.parts.keys():
crit.parts[k].value = v
crit.parts[k].comparisonValue = v
parts = Jeep(crit.parts)
result = list(self.selectObjects(parts)) # may modify parts
qc = CompoundQueryCriteria(parts)

Binary file not shown.

View file

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: $Id$\n"
"POT-Creation-Date: 2007-05-22 12:00 CET\n"
"PO-Revision-Date: 2012-03-28 12:00 CET\n"
"PO-Revision-Date: 2012-05-09 12:00 CET\n"
"Last-Translator: Helmut Merz <helmutm@cy55.de>\n"
"Language-Team: loops developers <helmutm@cy55.de>\n"
"MIME-Version: 1.0\n"
@ -266,6 +266,24 @@ msgstr "Daten des Video-Objekts bearbeiten"
msgid "Play Movie"
msgstr "Video abspielen"
msgid "Show Meeting Minutes..."
msgstr "Besprechungsprotokoll anzeigen..."
msgid "Show meeting minutes for this object."
msgstr "Besprechungsprotokoll für dieses Objekt anzeigen."
msgid "Task/Action"
msgstr "Aufgabe"
msgid "Who/When"
msgstr "Wer? Bis wann?"
msgid "Who?"
msgstr "Wer?"
msgid "When?"
msgstr "Wann?"
msgid "Favorites"
msgstr "Lesezeichen"
@ -398,6 +416,9 @@ msgstr "Status"
msgid "Save"
msgstr "Speichern"
msgid "Save Changes"
msgstr "Änderungen speichern"
msgid "Cancel"
msgstr "Abbrechen"

View file

@ -70,7 +70,7 @@ class MemberRegistrationManager(object):
if pfName is None:
pfName = options(self.principalfolder_key,
(self.default_principalfolder,))[0]
self.createPrincipal(pfName, userId, password, lastName, firstName)
self.createPrincipal(pfName, userId, password, lastName, firstName, useExisting=useExisting)
if not groups:
groups = options(self.groups_key, ())
self.setGroupsForPrincipal(pfName, userId, groups=groups)

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
# Copyright (c) 2012 Helmut Merz helmutm@cy55.de
#
# 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
@ -18,8 +18,6 @@
"""
View class(es) for work items.
$Id$
"""
from datetime import date
@ -235,9 +233,9 @@ class BaseWorkItemsView(object):
result['timeFromTo'] = (tsFrom, tsTo)
state = form.get('wi_state') or self.options.wi_state
if not state:
result['state'] = ['planned', 'accepted', 'running', 'done', 'done_x',
'finished', 'delegated', 'moved',
'cancelled']
result['state'] = ['planned', 'accepted', 'running', 'done',
'done_x', 'finished', 'delegated', 'moved', 'cancelled']
#, 'closed']
elif state != 'all':
result['state'] = state
return result

View file

@ -97,6 +97,12 @@
set_schema="loops.expert.report.IReportInstance" />
</zope:class>
<browser:page
name="meeting_minutes.html"
for="loops.interfaces.IConceptSchema"
class="loops.organize.work.meeting.MeetingMinutes"
permission="zope.View" />
<!-- setup -->
<zope:adapter factory="loops.organize.work.setup.SetupManager"

62
organize/work/meeting.pt Normal file
View file

@ -0,0 +1,62 @@
<html i18n:domain="loops">
<div metal:define-macro="content"
tal:define="report item/reportInstance;
reportView nocall:item">
<div tal:attributes="class string:content-$level;">
<metal:block use-macro="view/concept_macros/concepttitle" />
<metal:block use-macro="view/concept_macros/conceptfields" />
</div><br />
<div metal:use-macro="reportView/resultsRenderer" />
</div>
<div metal:define-macro="results">
<table class="report"
tal:define="results reportView/results">
<tr>
<th i18n:translate=""
style="border: 1px solid grey">Task/Action</th>
<th style="border: 1px solid grey"
i18n:translate="">Who?</th>
<th style="border: 1px solid grey"
i18n:translate="">When?</th>
<th style="border: 1px solid grey"
i18n:translate=""></th>
</tr>
<tal:task repeat="row results">
<tr tal:repeat="colname python: ('title', 'description',)">
<td style="border: 1px solid grey"
tal:define="col report/fields/?colname"
tal:attributes="class col/cssClass">
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</td>
<td style="border: 1px solid grey" />
<td style="border: 1px solid grey" />
<td style="border: 1px solid grey" />
</tr>
<tal:workitems define="col report/fields/workItems">
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</tal:workitems>
</tal:task>
</table>
</div>
<div metal:define-macro="subreport"
tal:define="results python:col.getValue(row)">
<tr class="listing" tal:repeat="row results">
<td tal:repeat="col results/displayedColumns"
tal:attributes="class col/cssClass"
style="border: 1px solid grey">
<metal:column use-macro="python:
reportView.getColumnRenderer(col)" />
</td>
</tr>
</div>
</html>

61
organize/work/meeting.py Normal file
View file

@ -0,0 +1,61 @@
#
# Copyright (c) 2012 Helmut Merz helmutm@cy55.de
#
# 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
#
"""
View class(es) for accessing tasks and work items as meeting minutes.
"""
from zope.app.pagetemplate import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy
from cybertools.browser.action import actions
from loops.browser.action import TargetAction
from loops.expert.browser.report import ResultsConceptView
from loops.util import _
meeting_template = ViewPageTemplateFile('meeting.pt')
actions.register('meeting_minutes', 'portlet', TargetAction,
title=_(u'Show Meeting Minutes...'),
description=_(u'Show meeting minutes for this object.'),
viewName='meeting_minutes.html',
)
class MeetingMinutes(ResultsConceptView):
reportName = 'meeting_minutes'
@Lazy
def meeting_macros(self):
return meeting_template.macros
@Lazy
def macro(self):
return self.meeting_macros['content']
@Lazy
def resultsRenderer(self):
return self.meeting_macros['results']
def getColumnRenderer(self, col):
renderer = col.renderer
if renderer == 'subreport':
return self.meeting_macros[renderer]
return self.result_macros[renderer]

View file

@ -33,11 +33,17 @@ from cybertools.util.date import timeStamp2Date
from cybertools.util.format import formatDate
from cybertools.util.jeep import Jeep
from loops.common import adapted, baseObject
from loops.expert.field import TargetField, TextField, UrlField, SubReportField
from loops.expert.field import TargetField, TextField, UrlField
from loops.expert.field import SubReport, SubReportField
from loops.expert.report import ReportInstance
from loops import util
class StateField(Field):
def getDisplayValue(self, row):
value = self.getValue(row)
return util._(value)
class DateField(Field):
part = 'date'
@ -101,6 +107,7 @@ dayTo = Field('dayTo', u'End Day',
executionSteps=['query'])
day = DateField('day', u'Day',
description=u'The day the work was done.',
cssClass='center',
executionSteps=['sort', 'output'])
timeStart = TimeField('start', u'Start',
description=u'The time the unit of work was started.',
@ -126,8 +133,9 @@ duration = DurationField('duration', u'Duration',
effort = DurationField('effort', u'Effort',
description=u'The effort of the work.',
executionSteps=['output', 'totals'])
state = Field('state', u'State',
state = StateField('state', u'State',
description=u'The state of the work.',
cssClass='center',
executionSteps=['query', 'output'])
@ -237,15 +245,44 @@ class WorkReportInstance(ReportInstance):
# meeting minutes
class MeetingMinutesWorkRow(WorkRow):
pass
class MeetingMinutesWork(WorkReportInstance, SubReport):
rowFactory = MeetingMinutesWorkRow
fields = Jeep((workTitle, party, day, state)) #description,
defaultOutputFields = fields
defaultSortCriteria = (day,)
states = ('planned', 'accepted', 'running', 'done',
'finished', 'closed', 'moved')
@property
def queryCriteria(self):
return CompoundQueryCriteria([])
def selectObjects(self, parts):
parts.pop('tasks', None)
t = self.parentRow.context
if t is not None:
return self.selectWorkItems(t, parts)
return []
taskTitle = UrlField('title', u'Title',
description=u'The short description of the task.',
cssClass='header-1',
executionSteps=['output'])
taskDescription = TextField('description', u'Description',
description=u'The long description of the task.',
cssClass='header-2',
executionSteps=['output'])
workItems = SubReportField('workItems', u'Work Items',
description=u'A list of work items belonging to the task.',
reportFactory=WorkReportInstance,
reportFactory=MeetingMinutesWork,
executionSteps=['output'])
@ -274,3 +311,4 @@ class MeetingMinutes(WorkReportInstance):
def selectObjects(self, parts):
return self.getTasks(parts)[1:]

View file

@ -213,20 +213,20 @@
(<span tal:content="python:
item.getUserForUserName(item.track.creator)['title']" />)</td>
</tr>
<tr tal:condition="python:state.name == 'delegated'">
<tr tal:condition="python:state.name in ('delegated', 'delegated_x')">
<td><span i18n:translate="">Delegated to</span>:</td>
<td><a tal:define="party python:view.getObjectForUid(item.targetWorkItem.party)"
tal:attributes="href python:view.getUrlForTarget(party)"
tal:content="party/title" /></td>
</tr>
<tr tal:condition="python:state.name == 'moved'">
<tr tal:condition="python:state.name in ('moved', 'moved_x')">
<td><span i18n:translate="">Moved To</span>:</td>
<td><a tal:define="task python:view.getObjectForUid(item.targetWorkItem.taskId)"
tal:attributes="href python:view.getUrlForTarget(task)"
tal:content="task/title" /></td>
</tr>
<tr tal:define="source item/sourceWorkItem;
isDelegated python:source and source.state == 'delegated'"
isDelegated python:source and source.state in ('delegated', 'delegated_x')"
tal:condition="source">
<td>
<span tal:condition="isDelegated"