1.1 --- a/EventAggregatorSupport/Filter.py Wed May 01 17:38:06 2013 +0200
1.2 +++ b/EventAggregatorSupport/Filter.py Fri May 03 16:37:36 2013 +0200
1.3 @@ -7,8 +7,16 @@
1.4 """
1.5
1.6 from DateSupport import DateTime, Timespan, TimespanCollection, \
1.7 - getCurrentDate, getCurrentMonth
1.8 -from MoinSupport import *
1.9 + getCurrentDate, getCurrentMonth, cmp_dates_as_day_start
1.10 +
1.11 +try:
1.12 + set
1.13 +except NameError:
1.14 + from sets import Set as set
1.15 +
1.16 +# Sortable values representing start and end limits of timespans/events.
1.17 +
1.18 +START, END = 0, 1
1.19
1.20 # Event filtering and limits.
1.21
1.22 @@ -189,38 +197,73 @@
1.23 """
1.24 Return a scale for the given coverage so that the times involved are
1.25 exposed. The scale consists of a list of non-overlapping timespans forming
1.26 - a contiguous period of time.
1.27 + a contiguous period of time, where each timespan is accompanied in a tuple
1.28 + by a limit and a list of original time details. Thus, the scale consists of
1.29 + (timespan, limit, set-of-times) tuples.
1.30 """
1.31
1.32 - times = set()
1.33 + times = {}
1.34 +
1.35 for timespan in coverage:
1.36 start, end = timespan.as_limits()
1.37
1.38 # Add either genuine times or dates converted to times.
1.39
1.40 if isinstance(start, DateTime):
1.41 - times.add(start)
1.42 + value = start
1.43 + key = value.to_utc(), START
1.44 else:
1.45 - times.add(start.as_start_of_day())
1.46 + value = start.as_start_of_day()
1.47 + key = value, START
1.48 +
1.49 + if not times.has_key(key):
1.50 + times[key] = set()
1.51 + times[key].add(value)
1.52
1.53 if isinstance(end, DateTime):
1.54 - times.add(end)
1.55 + value = end
1.56 + key = value.to_utc(), END
1.57 else:
1.58 - times.add(end.as_date().next_day())
1.59 + value = end.as_date().next_day()
1.60 + key = value, END
1.61
1.62 - times = list(times)
1.63 - times.sort(cmp_dates_as_day_start)
1.64 + if not times.has_key(key):
1.65 + times[key] = set()
1.66 + times[key].add(value)
1.67 +
1.68 + keys = times.keys()
1.69 + keys.sort(cmp_tuples_with_dates_as_day_start)
1.70
1.71 scale = []
1.72 first = 1
1.73 - start = None
1.74 - for time in times:
1.75 + start, start_limit = None, None
1.76 +
1.77 + for time, limit in keys:
1.78 if not first:
1.79 - scale.append(Timespan(start, time))
1.80 + scale.append((Timespan(start, time), limit, times[(start, start_limit)]))
1.81 else:
1.82 first = 0
1.83 - start = time
1.84 + start, start_limit = time, limit
1.85
1.86 return scale
1.87
1.88 +def cmp_tuples_with_dates_as_day_start(a, b):
1.89 +
1.90 + """
1.91 + Compare (datetime, limit) tuples, where identical datetimes are
1.92 + distinguished by the limit associated with them.
1.93 + """
1.94 +
1.95 + a_date, a_limit = a
1.96 + b_date, b_limit = b
1.97 + result = cmp_dates_as_day_start(a_date, b_date)
1.98 +
1.99 + if result == 0:
1.100 + if a_limit < b_limit:
1.101 + return -1
1.102 + else:
1.103 + return 1
1.104 +
1.105 + return result
1.106 +
1.107 # vim: tabstop=4 expandtab shiftwidth=4
2.1 --- a/EventAggregatorSupport/View.py Wed May 01 17:38:06 2013 +0200
2.2 +++ b/EventAggregatorSupport/View.py Fri May 03 16:37:36 2013 +0200
2.3 @@ -563,6 +563,8 @@
2.4 specific_start = self.calendar_start
2.5 specific_end = self.calendar_end
2.6
2.7 + multiday = self.resolution == "date" and len(specific_start.days_until(specific_end)) > 1
2.8 +
2.9 start = self.wider_calendar_start or self.original_calendar_start and specific_start
2.10 end = self.wider_calendar_end or self.original_calendar_end and specific_end
2.11
2.12 @@ -603,54 +605,60 @@
2.13 append(fmt.span(on=0))
2.14
2.15 if self.mode != "calendar":
2.16 - view_label = self.resolution == "date" and _("View day in calendar") or _("View as calendar")
2.17 + view_label = self.resolution == "date" and \
2.18 + (multiday and _("View days in calendar") or _("View day in calendar")) or \
2.19 + _("View as calendar")
2.20 append(fmt.span(on=1, css_class="event-view"))
2.21 append(linkToPage(request, page, view_label, calendar_link, onclick=calendar_update_link))
2.22 append(fmt.span(on=0))
2.23
2.24 if self.resolution == "date" and self.mode != "day":
2.25 + view_label = multiday and _("View days as calendar") or _("View day as calendar")
2.26 append(fmt.span(on=1, css_class="event-view"))
2.27 - append(linkToPage(request, page, _("View day as calendar"), specific_day_link, onclick=specific_day_update_link))
2.28 + append(linkToPage(request, page, view_label, specific_day_link, onclick=specific_day_update_link))
2.29 append(fmt.span(on=0))
2.30
2.31 if self.resolution != "date" and self.mode != "list" or self.resolution == "date":
2.32 - view_label = self.resolution == "date" and _("View day in list") or _("View as list")
2.33 + view_label = self.resolution == "date" and \
2.34 + (multiday and _("View days in list") or _("View day in list")) or \
2.35 + _("View as list")
2.36 append(fmt.span(on=1, css_class="event-view"))
2.37 append(linkToPage(request, page, view_label, list_link, onclick=list_update_link))
2.38 append(fmt.span(on=0))
2.39
2.40 if self.resolution == "date" and self.mode != "list":
2.41 + view_label = multiday and _("View days as list") or _("View day as list")
2.42 append(fmt.span(on=1, css_class="event-view"))
2.43 - append(linkToPage(request, page, _("View day as list"),
2.44 - specific_list_link, onclick=specific_list_update_link
2.45 - ))
2.46 + append(linkToPage(request, page, view_label, specific_list_link, onclick=specific_list_update_link))
2.47 append(fmt.span(on=0))
2.48
2.49 if self.resolution != "date" and self.mode != "table" or self.resolution == "date":
2.50 - view_label = self.resolution == "date" and _("View day in table") or _("View as table")
2.51 + view_label = self.resolution == "date" and \
2.52 + (multiday and _("View days in table") or _("View day in table")) or \
2.53 + _("View as table")
2.54 append(fmt.span(on=1, css_class="event-view"))
2.55 append(linkToPage(request, page, view_label, table_link, onclick=table_update_link))
2.56 append(fmt.span(on=0))
2.57
2.58 if self.resolution == "date" and self.mode != "table":
2.59 + view_label = multiday and _("View days as table") or _("View day as table")
2.60 append(fmt.span(on=1, css_class="event-view"))
2.61 - append(linkToPage(request, page, _("View day as table"),
2.62 - specific_table_link, onclick=specific_table_update_link
2.63 - ))
2.64 + append(linkToPage(request, page, view_label, specific_table_link, onclick=specific_table_update_link))
2.65 append(fmt.span(on=0))
2.66
2.67 if self.map_name:
2.68 if self.resolution != "date" and self.mode != "map" or self.resolution == "date":
2.69 - view_label = self.resolution == "date" and _("View day in map") or _("View as map")
2.70 + view_label = self.resolution == "date" and \
2.71 + (multiday and _("View days in map") or _("View day in map")) or \
2.72 + _("View as map")
2.73 append(fmt.span(on=1, css_class="event-view"))
2.74 append(linkToPage(request, page, view_label, map_link, onclick=map_update_link))
2.75 append(fmt.span(on=0))
2.76
2.77 if self.resolution == "date" and self.mode != "map":
2.78 + view_label = multiday and _("View days as map") or _("View day as map")
2.79 append(fmt.span(on=1, css_class="event-view"))
2.80 - append(linkToPage(request, page, _("View day as map"),
2.81 - specific_map_link, onclick=specific_map_update_link
2.82 - ))
2.83 + append(linkToPage(request, page, view_label, specific_map_link, onclick=specific_map_update_link))
2.84 append(fmt.span(on=0))
2.85
2.86 append(fmt.div(on=0))
2.87 @@ -1294,7 +1302,7 @@
2.88
2.89 day_rows = []
2.90
2.91 - for period in scale:
2.92 + for period, limit, times in scale:
2.93
2.94 # Ignore timespans before this day.
2.95
2.96 @@ -1318,7 +1326,7 @@
2.97 rowspans[event] += 1
2.98 day_row.append((location, event))
2.99
2.100 - day_rows.append((period, day_row))
2.101 + day_rows.append((period, day_row, times))
2.102
2.103 # Output the locations.
2.104
2.105 @@ -1345,23 +1353,21 @@
2.106
2.107 # Output the periods with event details.
2.108
2.109 - period = None
2.110 + last_period = period = None
2.111 events_written = set()
2.112
2.113 - for period, day_row in day_rows:
2.114 -
2.115 - # Write an empty heading for the start of the day where the first
2.116 - # applicable timespan starts before this day.
2.117 -
2.118 - if period.start < date:
2.119 - append(fmt.table_row(on=1))
2.120 - append(self.writeDayScaleHeading(""))
2.121 -
2.122 - # Otherwise, write a heading describing the time.
2.123 -
2.124 + for period, day_row, times in day_rows:
2.125 +
2.126 + # Write a heading describing the time.
2.127 +
2.128 + append(fmt.table_row(on=1))
2.129 +
2.130 + # Show times only for distinct periods.
2.131 +
2.132 + if not last_period or period.start != last_period.start:
2.133 + append(self.writeDayScaleHeading(times))
2.134 else:
2.135 - append(fmt.table_row(on=1))
2.136 - append(self.writeDayScaleHeading(period.start.time_string()))
2.137 + append(self.writeDayScaleHeading([]))
2.138
2.139 append(self.writeDaySpacer())
2.140
2.141 @@ -1382,12 +1388,14 @@
2.142
2.143 append(fmt.table_row(on=0))
2.144
2.145 + last_period = period
2.146 +
2.147 # Write a final time heading if the last period ends in the current day.
2.148
2.149 if period is not None:
2.150 if period.end == date:
2.151 append(fmt.table_row(on=1))
2.152 - append(self.writeDayScaleHeading(period.end.time_string()))
2.153 + append(self.writeDayScaleHeading(times))
2.154
2.155 for slot in day_row:
2.156 append(self.writeDaySpacer())
2.157 @@ -1397,7 +1405,7 @@
2.158
2.159 return "".join(output)
2.160
2.161 - def writeDayScaleHeading(self, heading):
2.162 + def writeDayScaleHeading(self, times):
2.163 page = self.page
2.164 fmt = page.request.formatter
2.165
2.166 @@ -1405,7 +1413,15 @@
2.167 append = output.append
2.168
2.169 append(fmt.table_cell(on=1, attrs={"class" : "event-scale-heading"}))
2.170 - append(fmt.text(heading))
2.171 +
2.172 + first = 1
2.173 + for t in times:
2.174 + if isinstance(t, DateTime):
2.175 + if not first:
2.176 + append(fmt.linebreak(0))
2.177 + append(fmt.text(t.time_string()))
2.178 + first = 0
2.179 +
2.180 append(fmt.table_cell(on=0))
2.181
2.182 return "".join(output)