[gen] Calendar field: more work on multi-events and validation within timeline calendars.

This commit is contained in:
Gaetan Delannay 2015-03-04 23:35:52 +01:00
parent 93b2740906
commit bcf2952980
10 changed files with 113 additions and 51 deletions

View file

@ -93,6 +93,10 @@ class Other:
info.name = eventNames[eventType]
res.append(info)
def mayValidate(self):
'''Is validation enabled for this other calendar?'''
return self.field.mayValidate(self.obj)
# ------------------------------------------------------------------------------
class Event(Persistent):
'''An event as will be stored in the database'''
@ -159,19 +163,15 @@ class Calendar(Field):
# Legend for a timeline calendar
pxTimelineLegend = Px('''
<table align="center" class="discreet"
var="legendTypes=[et for et in allEventTypes if et in colors]">
<tr for="row in field.splitList(legendTypes, 4)">
<x for="eventType in row">
<td> <!-- A colored cell (as mono-cell sub-table) -->
<table>
<tr height="9px">
<td width="9px"
style=":'background-color: %s' % colors[eventType]">&nbsp;</td>
</tr>
</table>
</td>
var="items=field.getLegendItems(allEventTypes, allEventNames, \
colors, url, _)">
<tr for="row in field.splitList(items, 4)">
<x for="item in row">
<td><table> <!-- A colored cell (as mono-cell sub-table) -->
<tr height="9px"><td width="9px" style=":item.style">&nbsp;</td></tr>
</table></td>
<!-- The event name -->
<td>:allEventNames[eventType]</td>
<td width="115px">:item.name</td>
</x>
</tr>
</table>''')
@ -201,7 +201,8 @@ class Calendar(Field):
<!-- Other calendars -->
<x for="otherGroup in others">
<tr for="other in otherGroup"
var2="tlName=field.getTimelineName(other)">
var2="tlName=field.getTimelineName(other);
mayValidate=mayValidate and other.mayValidate()">
<td class="tlLeft">::tlName</td>
<!-- A cell in this other calendar -->
<x for="date in grid"
@ -211,7 +212,7 @@ class Calendar(Field):
var2="events=field.getOtherEventsAt(zobj, date, other, \
allEventNames, render, colors)"
style=":field.getCellStyle(zobj, date, render, \
events)">::field.getTimelineCell(events)</td>
events)">::field.getTimelineCell(date, other, events, mayValidate)</td>
</x>
<td class="tlRight">::tlName</td>
</tr>
@ -682,11 +683,63 @@ class Calendar(Field):
return '<a href="%s">%s</a>' % (other.obj.url, other.obj.title)
return self.timelineName(self, other)
def getTimelineCell(self, events):
'''Gets the content of a cell in a timeline calendar.'''
# Currently a single event is allowed
if not events or not events[0].symbol: return ''
return events[0].symbol
def getTimelineCell(self, date, other, events, mayValidate):
'''Gets the content of a cell in a timeline calendar'''
if events and mayValidate:
# If at least one event from p_events is in the validation schema,
# propose a unique checkbox, that will allow to validate or not all
# validable events at p_date.
for info in events:
if info.event.eventType in other.field.validation.schema:
return '<input type="checkbox" checked="checked" class="smallbox"/>'
return ''
# When there are multiple events, a background image is already shown
if not events or (len(events) > 1): return ''
# A single event: if not colored, show a symbol
return events[0].symbol or ''
def getLegendItems(self, allEventTypes, allEventNames, colors, url, _):
'''Gets information needed to produce the legend for a timeline.'''
# Produce one legend item by event type shown and colored
res = []
for eventType in allEventTypes:
if eventType not in colors: continue
res.append(Object(name=allEventNames[eventType],
style='background-color: %s' % colors[eventType]))
# Add the background indicating that several events are hidden behind
# the timeline cell
res.append(Object(name=_('several_events'),
style=url('angled', bg=True)))
return res
def getTimelineMonths(self, grid, obj):
'''Given the p_grid of dates, this method returns the list of
corresponding months.'''
res = []
for date in grid:
if not res:
# Get the month correspoding to the first day in the grid
m = Object(month=date.aMonth(), colspan=1, year=date.year())
res.append(m)
else:
# Augment current month' colspan or create a new one
current = res[-1]
if date.aMonth() == current.month:
current.colspan += 1
else:
m = Object(month=date.aMonth(), colspan=1, year=date.year())
res.append(m)
# Replace month short names by translated names whose format may vary
# according to colspan (a higher colspan allow us to produce a longer
# month name).
for m in res:
text = '%s %d' % (obj.translate('month_%s' % m.month), m.year)
if m.colspan < 6:
# Short version: a single letter with an acronym
m.month = '<acronym title="%s">%s</acronym>' % (text, text[0])
else:
m.month = text
return res
def getAdditionalInfoAt(self, obj, date, preComputed):
'''If the user has specified a method in self.additionalInfo, we call
@ -1144,7 +1197,13 @@ class Calendar(Field):
def getCellStyle(self, obj, date, render, events):
'''Gets the cell style to apply to the cell corresponding to p_date.'''
if render != 'timeline': return '' # Currently, for timelines only
if not events or (len(events) > 1): return ''
if not events: return ''
elif len(events) > 1:
# Return a special background indicating that several events are
# hidden behing this cell.
return 'background-image: url(%s/ui/angled.png)' % \
obj.getTool().getSiteUrl()
else:
event = events[0]
return event.bgColor and ('background-color: %s' % event.bgColor) or ''
@ -1163,35 +1222,6 @@ class Calendar(Field):
res.append('cellDashed')
return ' '.join(res)
def getTimelineMonths(self, grid, obj):
'''Given the p_grid of dates, this method returns the list of
corresponding months.'''
res = []
for date in grid:
if not res:
# Get the month correspoding to the first day in the grid
m = Object(month=date.aMonth(), colspan=1, year=date.year())
res.append(m)
else:
# Augment current month' colspan or create a new one
current = res[-1]
if date.aMonth() == current.month:
current.colspan += 1
else:
m = Object(month=date.aMonth(), colspan=1, year=date.year())
res.append(m)
# Replace month short names by translated names whose format may vary
# according to colspan (a higher colspan allow us to produce a longer
# month name).
for m in res:
text = '%s %d' % (obj.translate('month_%s' % m.month), m.year)
if m.colspan < 6:
# Short version: a single letter with an acronym
m.month = '<acronym title="%s">%s</acronym>' % (text, text[0])
else:
m.month = text
return res
def splitList(self, l, sub): return sutils.splitList(l, sub)
def mayValidate(self, obj):
'''May the currently logged user validate wish events ?'''

View file

@ -715,6 +715,10 @@ msgstr ""
msgid "del_next_events"
msgstr ""
#. Default: "Several events"
msgid "several_events"
msgstr ""
#. Default: "Timeslot"
msgid "timeslot"
msgstr ""

View file

@ -715,6 +715,10 @@ msgstr ""
msgid "del_next_events"
msgstr ""
#. Default: "Several events"
msgid "several_events"
msgstr ""
#. Default: "Timeslot"
msgid "timeslot"
msgstr ""

View file

@ -715,6 +715,10 @@ msgstr ""
msgid "del_next_events"
msgstr ""
#. Default: "Several events"
msgid "several_events"
msgstr ""
#. Default: "Timeslot"
msgid "timeslot"
msgstr ""

View file

@ -716,6 +716,10 @@ msgstr "Extend the event on the following number of days (leave blank to create
msgid "del_next_events"
msgstr "Also delete successive events of the same type."
#. Default: "Several events"
msgid "several_events"
msgstr "Several events"
#. Default: "Timeslot"
msgid "timeslot"
msgstr "Timeslot"

View file

@ -715,6 +715,10 @@ msgstr ""
msgid "del_next_events"
msgstr ""
#. Default: "Several events"
msgid "several_events"
msgstr ""
#. Default: "Timeslot"
msgid "timeslot"
msgstr ""

View file

@ -716,6 +716,10 @@ msgstr "Étendre l'événement sur le nombre de jours suivants (laissez vide pou
msgid "del_next_events"
msgstr "Supprimer aussi les événements successifs de même type"
#. Default: "Several events"
msgid "several_events"
msgstr "Plusieurs événements"
#. Default: "Timeslot"
msgid "timeslot"
msgstr "Plage horaire"

View file

@ -715,6 +715,10 @@ msgstr ""
msgid "del_next_events"
msgstr ""
#. Default: "Several events"
msgid "several_events"
msgstr ""
#. Default: "Timeslot"
msgid "timeslot"
msgstr ""

View file

@ -715,6 +715,10 @@ msgstr "Het event uitbreiden naar de volgende dagen (leeg laten om een event aan
msgid "del_next_events"
msgstr "Verwijder ook alle opeenvolgende events van hetzelfde type"
#. Default: "Several events"
msgid "several_events"
msgstr ""
#. Default: "Timeslot"
msgid "timeslot"
msgstr ""

BIN
gen/ui/angled.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B