merge branch master
This commit is contained in:
commit
221ee291eb
10 changed files with 4515 additions and 35 deletions
|
@ -25,6 +25,7 @@ from zope.cachedescriptors.property import Lazy
|
||||||
|
|
||||||
from cybertools.composer.interfaces import IInstance
|
from cybertools.composer.interfaces import IInstance
|
||||||
from cybertools.composer.report.base import BaseQueryCriteria
|
from cybertools.composer.report.base import BaseQueryCriteria
|
||||||
|
from cybertools.util.jeep import Jeep
|
||||||
|
|
||||||
|
|
||||||
class BaseRow(object):
|
class BaseRow(object):
|
||||||
|
@ -63,7 +64,7 @@ class Row(BaseRow):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def allColumns(self):
|
def allColumns(self):
|
||||||
return self.partent.context.getAllFields()
|
return self.parent.context.getAllFields()
|
||||||
|
|
||||||
def useRowProperty(self, attr):
|
def useRowProperty(self, attr):
|
||||||
return getattr(self, attr)
|
return getattr(self, attr)
|
||||||
|
@ -192,7 +193,7 @@ class ResultSet(object):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def displayedColumns(self):
|
def displayedColumns(self):
|
||||||
return self.context.getActiveOutputFields()
|
return Jeep(self.context.getActiveOutputFields())
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def groupColumns(self):
|
def groupColumns(self):
|
||||||
|
|
|
@ -187,6 +187,7 @@ class FieldInstance(object):
|
||||||
|
|
||||||
clientInstance = clientContext = request = None
|
clientInstance = clientContext = request = None
|
||||||
value = undefined
|
value = undefined
|
||||||
|
request = None
|
||||||
|
|
||||||
def __init__(self, context):
|
def __init__(self, context):
|
||||||
self.context = context
|
self.context = context
|
||||||
|
@ -433,5 +434,5 @@ class DropdownFieldInstance(FieldInstance):
|
||||||
for item in items:
|
for item in items:
|
||||||
if str(item['token']) == str(value):
|
if str(item['token']) == str(value):
|
||||||
return item['title']
|
return item['title']
|
||||||
return value
|
return value or u''
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,13 @@ View definitions for generation of documents.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import quopri
|
||||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.publisher.browser import BrowserPage
|
from zope.publisher.browser import BrowserPage
|
||||||
|
|
||||||
word_template = ViewPageTemplateFile('word_page.pt')
|
word_template = ViewPageTemplateFile('word_page.pt')
|
||||||
|
body_template = ViewPageTemplateFile('word_body.pt')
|
||||||
|
|
||||||
|
|
||||||
class Base(BrowserPage):
|
class Base(BrowserPage):
|
||||||
|
@ -34,17 +36,38 @@ class Base(BrowserPage):
|
||||||
encoding = 'ISO8859-15'
|
encoding = 'ISO8859-15'
|
||||||
|
|
||||||
def __call__(self, *args, **kw):
|
def __call__(self, *args, **kw):
|
||||||
data = self.index(*args, **kw).encode(self.encoding)
|
content = self.index(*args, **kw).encode(self.encoding)
|
||||||
self.setHeader(data)
|
self.setHeader(content)
|
||||||
return data
|
return content
|
||||||
|
|
||||||
|
|
||||||
class WordDocument(Base):
|
class WordDocument(Base):
|
||||||
|
|
||||||
isToplevel = True
|
isToplevel = True
|
||||||
index = word_template
|
index = word_template
|
||||||
|
bodyTemplate = body_template
|
||||||
showLinks = False
|
showLinks = False
|
||||||
|
|
||||||
|
def embed(self, *args, **kw):
|
||||||
|
self.encoding = 'Windows-1252'
|
||||||
|
bodyMarker = 'lxdoc_body'
|
||||||
|
content = self.bodyTemplate(*args, **kw).encode(self.encoding)
|
||||||
|
baseDocument = self.readDocTemplate()
|
||||||
|
document = baseDocument.replace(bodyMarker,
|
||||||
|
self.quopri(content))
|
||||||
|
self.setHeader(document)
|
||||||
|
return document
|
||||||
|
|
||||||
|
def quopri(self, s):
|
||||||
|
return s.replace('="', '=3D"')
|
||||||
|
|
||||||
|
def readDocTemplate(self):
|
||||||
|
path = os.path.join(os.path.dirname(__file__), 'document.mht')
|
||||||
|
f = open(path, 'r')
|
||||||
|
doc = f.read()
|
||||||
|
f.close()
|
||||||
|
return doc
|
||||||
|
|
||||||
def setHeader(self, data, filename='document'):
|
def setHeader(self, data, filename='document'):
|
||||||
fn = '%s.doc' % filename
|
fn = '%s.doc' % filename
|
||||||
response = self.request.response
|
response = self.request.response
|
||||||
|
@ -75,4 +98,3 @@ class WordDocument(Base):
|
||||||
css = f.read()
|
css = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
return css
|
return css
|
||||||
|
|
||||||
|
|
4399
docgen/document.mht
Executable file
4399
docgen/document.mht
Executable file
File diff suppressed because it is too large
Load diff
|
@ -78,6 +78,10 @@ th {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.MsoHeader, p.MsoHeader {
|
||||||
|
mso-style-noshow:yes;
|
||||||
|
}
|
||||||
|
|
||||||
span.MsoFootnoteReference {
|
span.MsoFootnoteReference {
|
||||||
mso-style-noshow:yes;
|
mso-style-noshow:yes;
|
||||||
vertical-align: super;
|
vertical-align: super;
|
||||||
|
|
1
docgen/word_body.pt
Normal file
1
docgen/word_body.pt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<metal:content use-macro="view/content" />
|
|
@ -17,7 +17,8 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="doc">
|
<body class="doc">
|
||||||
<div class="Section2">
|
<div class="Section2"
|
||||||
|
tal:omit-tag="view/omitSectionElement|nothing">
|
||||||
<metal:content use-macro="view/content" />
|
<metal:content use-macro="view/content" />
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -342,6 +342,7 @@ application/x-123 wk
|
||||||
application/x-abiword abw
|
application/x-abiword abw
|
||||||
application/x-apple-diskimage dmg
|
application/x-apple-diskimage dmg
|
||||||
application/x-bcpio bcpio
|
application/x-bcpio bcpio
|
||||||
|
application/x-binary repx
|
||||||
application/x-bittorrent torrent
|
application/x-bittorrent torrent
|
||||||
application/x-cdf cdf
|
application/x-cdf cdf
|
||||||
application/x-cdlink vcd
|
application/x-cdlink vcd
|
||||||
|
|
|
@ -530,16 +530,21 @@ class IWorkItem(ITrack):
|
||||||
'by its name or ID.')
|
'by its name or ID.')
|
||||||
state = Attribute('The current state the work item is in.')
|
state = Attribute('The current state the work item is in.')
|
||||||
# standard attributes
|
# standard attributes
|
||||||
|
workItemType = Attribute('The type of the work item '
|
||||||
|
'(work, event, deadline).')
|
||||||
title = Attribute('A short text characterizing the work item.')
|
title = Attribute('A short text characterizing the work item.')
|
||||||
description = Attribute('A note about what has to be done, and why...')
|
description = Attribute('A note about what has to be done, and why...')
|
||||||
|
deadline = Attribute('When the work has to be finished.')
|
||||||
start = Attribute('When the work was started.')
|
start = Attribute('When the work was started.')
|
||||||
end = Attribute('When the work was finished.')
|
end = Attribute('When the work was finished.')
|
||||||
duration = Attribute('How long it took to finish the work.')
|
duration = Attribute('How long it took to finish the work.')
|
||||||
effort = Attribute('How much effort (time units) it took to finish the work.')
|
effort = Attribute('How much effort (time units) it took '
|
||||||
|
'to finish the work.')
|
||||||
comment = Attribute('A note about what has been done, and why...')
|
comment = Attribute('A note about what has been done, and why...')
|
||||||
# work item handling
|
# work item handling
|
||||||
creator = Attribute('The party that has set up the work item.')
|
creator = Attribute('The party that has set up the work item.')
|
||||||
created = Attribute('The timeStamp of the initial creation of the work item.')
|
created = Attribute('The timeStamp of the initial creation '
|
||||||
|
'of the work item.')
|
||||||
newTask = Attribute('Optional: a new task that has been created based '
|
newTask = Attribute('Optional: a new task that has been created based '
|
||||||
'on this work item.')
|
'on this work item.')
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ from cybertools.stateful.definition import State, Transition
|
||||||
from cybertools.stateful.interfaces import IStatesDefinition
|
from cybertools.stateful.interfaces import IStatesDefinition
|
||||||
from cybertools.tracking.btree import Track, getTimeStamp
|
from cybertools.tracking.btree import Track, getTimeStamp
|
||||||
from cybertools.tracking.interfaces import ITrackingStorage
|
from cybertools.tracking.interfaces import ITrackingStorage
|
||||||
|
from cybertools.util.jeep import Jeep
|
||||||
|
|
||||||
_not_found = object()
|
_not_found = object()
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ def workItemStates():
|
||||||
return StatesDefinition('workItemStates',
|
return StatesDefinition('workItemStates',
|
||||||
State('new', 'new',
|
State('new', 'new',
|
||||||
('plan', 'accept', 'start', 'work', 'finish', 'delegate',
|
('plan', 'accept', 'start', 'work', 'finish', 'delegate',
|
||||||
'cancel'),
|
'cancel', 'reopen'),
|
||||||
color='red'),
|
color='red'),
|
||||||
State('planned', 'planned',
|
State('planned', 'planned',
|
||||||
('plan', 'accept', 'start', 'work', 'finish', 'delegate',
|
('plan', 'accept', 'start', 'work', 'finish', 'delegate',
|
||||||
|
@ -63,11 +64,11 @@ def workItemStates():
|
||||||
State('cancelled', 'cancelled',
|
State('cancelled', 'cancelled',
|
||||||
('plan', 'accept', 'start', 'work', 'move', 'modify', 'close'),
|
('plan', 'accept', 'start', 'work', 'move', 'modify', 'close'),
|
||||||
color='grey'),
|
color='grey'),
|
||||||
State('closed', 'closed', (), color='lightblue'),
|
State('closed', 'closed', ('reopen',), color='lightblue'),
|
||||||
# not directly reachable states:
|
# not directly reachable states:
|
||||||
State('delegated', 'delegated',
|
State('delegated', 'delegated',
|
||||||
('plan', 'accept', 'start', 'work', 'finish', 'close',
|
('plan', 'accept', #'start', 'work', 'finish',
|
||||||
'delegate', 'move', 'cancel', 'modify'),
|
'close', 'delegate', 'move', 'cancel', 'modify'),
|
||||||
color='purple'),
|
color='purple'),
|
||||||
State('delegated_x', 'delegated', (), color='purple'),
|
State('delegated_x', 'delegated', (), color='purple'),
|
||||||
State('moved', 'moved',
|
State('moved', 'moved',
|
||||||
|
@ -82,7 +83,7 @@ def workItemStates():
|
||||||
# transitions:
|
# transitions:
|
||||||
Transition('plan', 'plan', 'planned'),
|
Transition('plan', 'plan', 'planned'),
|
||||||
Transition('accept', 'accept', 'accepted'),
|
Transition('accept', 'accept', 'accepted'),
|
||||||
Transition('start', 'start working', 'running'),
|
Transition('start', 'start working', 'running'), # obsolete?
|
||||||
Transition('work', 'work', 'done'),
|
Transition('work', 'work', 'done'),
|
||||||
Transition('finish', 'finish', 'finished'),
|
Transition('finish', 'finish', 'finished'),
|
||||||
Transition('cancel', 'cancel', 'cancelled'),
|
Transition('cancel', 'cancel', 'cancelled'),
|
||||||
|
@ -90,10 +91,12 @@ def workItemStates():
|
||||||
Transition('delegate', 'delegate', 'planned'),
|
Transition('delegate', 'delegate', 'planned'),
|
||||||
Transition('move', 'move', 'planned'),
|
Transition('move', 'move', 'planned'),
|
||||||
Transition('close', 'close', 'closed'),
|
Transition('close', 'close', 'closed'),
|
||||||
|
Transition('reopen', 're-open', 'planned'),
|
||||||
initialState='new')
|
initialState='new')
|
||||||
|
|
||||||
|
|
||||||
fieldNames = ['title', 'description', 'start', 'end', 'duration', 'effort',
|
fieldNames = ['title', 'description', 'deadline', 'start', 'end',
|
||||||
|
'duration', 'effort',
|
||||||
'comment', 'party'] # for use in editingRules
|
'comment', 'party'] # for use in editingRules
|
||||||
|
|
||||||
# meaning: - not editable, value=default
|
# meaning: - not editable, value=default
|
||||||
|
@ -102,22 +105,55 @@ fieldNames = ['title', 'description', 'start', 'end', 'duration', 'effort',
|
||||||
# . default (may be empty)
|
# . default (may be empty)
|
||||||
|
|
||||||
editingRules = dict(
|
editingRules = dict(
|
||||||
plan = {'*': '++.....+'},
|
plan = {'*': '+++.....+'},
|
||||||
accept = {'*': '++.....-',
|
accept = {'*': '+++.....-',
|
||||||
'planned': '++++++.-',
|
'planned': '+++++++.-',
|
||||||
'accepted': '++++++.-'},
|
'accepted': '+++++++.-'},
|
||||||
start = {'*': '++./...-'},
|
start = {'*': '+++./...-'},
|
||||||
work = {'*': '++.....-',
|
work = {'*': '+++.....-',
|
||||||
'running': '+++....-'},
|
'running': '++++....-'},
|
||||||
finish = {'*': '++.....-',
|
finish = {'*': '+++.....-',
|
||||||
'running': '+++....-'},
|
'running': '++++....-'},
|
||||||
cancel = {'*': '++////./'},
|
cancel = {'*': '+++////./'},
|
||||||
modify = {'*': '++++++++'},
|
modify = {'*': '+++++++++'},
|
||||||
delegate= {'*': '++......'},
|
delegate= {'*': '+++++++.+'},
|
||||||
close = {'*': '++////./'},
|
move = {'*': '+++++++.-'},
|
||||||
|
close = {'*': '+++////./'},
|
||||||
|
reopen = {'*': '+++////./'},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class WorkItemType(object):
|
||||||
|
""" Specify the type of a work item.
|
||||||
|
|
||||||
|
The work item type controls which actions (transitions)
|
||||||
|
and fields are available for a certain work item.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, title, description=u'',
|
||||||
|
actions=None, fields=None, indicator=None):
|
||||||
|
self.name = name
|
||||||
|
self.title = title
|
||||||
|
self.description = description
|
||||||
|
self.actions = actions or list(editingRules)
|
||||||
|
self.fields = fields or ('deadline', 'start-end', 'duration-effort')
|
||||||
|
self.indicator = indicator
|
||||||
|
|
||||||
|
workItemTypes = Jeep((
|
||||||
|
WorkItemType('work', u'Unit of Work', indicator='work_work'),
|
||||||
|
WorkItemType('scheduled', u'Scheduled Event',
|
||||||
|
actions=('plan', 'accept', 'finish', 'cancel',
|
||||||
|
'modify', 'delegate', 'move', 'close', 'reopen'),
|
||||||
|
fields =('start-end', 'duration-effort',),
|
||||||
|
indicator='work_event'),
|
||||||
|
WorkItemType('deadline', u'Deadline',
|
||||||
|
actions=('plan', 'accept', 'finish', 'cancel',
|
||||||
|
'modify', 'delegate', 'move', 'close', 'reopen'),
|
||||||
|
fields =('deadline',),
|
||||||
|
indicator='work_deadline')
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
class WorkItem(Stateful, Track):
|
class WorkItem(Stateful, Track):
|
||||||
""" A work item that may be stored as a track in a tracking storage.
|
""" A work item that may be stored as a track in a tracking storage.
|
||||||
"""
|
"""
|
||||||
|
@ -130,7 +166,8 @@ class WorkItem(Stateful, Track):
|
||||||
typeInterface = IWorkItem
|
typeInterface = IWorkItem
|
||||||
statesDefinition = 'organize.workItemStates'
|
statesDefinition = 'organize.workItemStates'
|
||||||
|
|
||||||
initAttributes = set(['party', 'title', 'description', 'start', 'end',
|
initAttributes = set(['workItemType', 'party', 'title', 'description',
|
||||||
|
'deadline', 'start', 'end',
|
||||||
'duration', 'effort'])
|
'duration', 'effort'])
|
||||||
|
|
||||||
def __init__(self, taskId, runId, userName, data):
|
def __init__(self, taskId, runId, userName, data):
|
||||||
|
@ -143,6 +180,10 @@ class WorkItem(Stateful, Track):
|
||||||
return component.getUtility(IStatesDefinition,
|
return component.getUtility(IStatesDefinition,
|
||||||
name=self.statesDefinition)
|
name=self.statesDefinition)
|
||||||
|
|
||||||
|
def getWorkItemType(self):
|
||||||
|
name = self.workItemType
|
||||||
|
return name and workItemTypes[name] or None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def party(self):
|
def party(self):
|
||||||
return self.userName
|
return self.userName
|
||||||
|
@ -194,7 +235,6 @@ class WorkItem(Stateful, Track):
|
||||||
self.state = self.state + '_x'
|
self.state = self.state + '_x'
|
||||||
self.reindex('state')
|
self.reindex('state')
|
||||||
new.doTransition(action)
|
new.doTransition(action)
|
||||||
#new.reindex('state')
|
|
||||||
new.reindex()
|
new.reindex()
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
@ -230,17 +270,18 @@ class WorkItem(Stateful, Track):
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def move(self, userName, **kw):
|
def move(self, userName, **kw):
|
||||||
moved = self.createNew('move', userName, **kw)
|
xkw = dict(kw)
|
||||||
|
for k in ('deadline', 'start', 'end'):
|
||||||
|
xkw.pop(k, None) # do not change on source item
|
||||||
|
moved = self.createNew('move', userName, **xkw)
|
||||||
moved.userName = self.userName
|
moved.userName = self.userName
|
||||||
moved.state = 'moved'
|
moved.state = 'moved'
|
||||||
#moved.reindex('state')
|
|
||||||
moved.reindex()
|
moved.reindex()
|
||||||
task = kw.pop('task', None)
|
task = kw.pop('task', None)
|
||||||
new = moved.createNew(None, userName, taskId=task, runId=0, **kw)
|
new = moved.createNew(None, userName, taskId=task, runId=0, **kw)
|
||||||
new.userName = self.userName
|
new.userName = self.userName
|
||||||
new.data['source'] = moved.name
|
new.data['source'] = moved.name
|
||||||
new.state = self.state
|
new.state = self.state
|
||||||
#new.reindex('state')
|
|
||||||
new.reindex()
|
new.reindex()
|
||||||
moved.data['target'] = new.name
|
moved.data['target'] = new.name
|
||||||
if self.state in ('planned', 'accepted', 'delegated', 'moved', 'done'):
|
if self.state in ('planned', 'accepted', 'delegated', 'moved', 'done'):
|
||||||
|
@ -274,7 +315,7 @@ class WorkItem(Stateful, Track):
|
||||||
if party is not None:
|
if party is not None:
|
||||||
self.userName = party
|
self.userName = party
|
||||||
self.reindex('userName')
|
self.reindex('userName')
|
||||||
start = kw.get('start')
|
start = kw.get('start') or kw.get('deadline') # TODO: check OK?
|
||||||
if start is not None:
|
if start is not None:
|
||||||
self.timeStamp = start
|
self.timeStamp = start
|
||||||
self.reindex('timeStamp')
|
self.reindex('timeStamp')
|
||||||
|
@ -293,6 +334,10 @@ class WorkItem(Stateful, Track):
|
||||||
if copyData is None:
|
if copyData is None:
|
||||||
copyData = self.initAttributes
|
copyData = self.initAttributes
|
||||||
newData = {}
|
newData = {}
|
||||||
|
start = kw.get('start')
|
||||||
|
deadline = kw.get('deadline')
|
||||||
|
if not start and deadline:
|
||||||
|
kw['start'] = deadline
|
||||||
for k in self.initAttributes.union(set(['comment'])):
|
for k in self.initAttributes.union(set(['comment'])):
|
||||||
v = kw.get(k, _not_found)
|
v = kw.get(k, _not_found)
|
||||||
if v is _not_found and k in copyData:
|
if v is _not_found and k in copyData:
|
||||||
|
|
Loading…
Add table
Reference in a new issue