1.1 --- a/EventAggregatorSupport.py Sun Aug 08 17:07:59 2010 +0200
1.2 +++ b/EventAggregatorSupport.py Fri Oct 22 01:13:28 2010 +0200
1.3 @@ -94,6 +94,14 @@
1.4 else:
1.5 return int(x)
1.6
1.7 +def sort_none_first(x, y):
1.8 + if x is None:
1.9 + return -1
1.10 + elif y is None:
1.11 + return 1
1.12 + else:
1.13 + return cmp(x, y)
1.14 +
1.15 # Utility classes and associated functions.
1.16
1.17 class Form:
1.18 @@ -841,6 +849,8 @@
1.19
1.20 return min(first, last), last
1.21
1.22 +# NOTE: Support coverage using times within days.
1.23 +
1.24 def getCoverage(start, end, events):
1.25
1.26 """
1.27 @@ -850,7 +860,7 @@
1.28 of the form (set of covered days, events).
1.29 """
1.30
1.31 - all_events = []
1.32 + all_events = {}
1.33 full_coverage = set()
1.34
1.35 # Get event details.
1.36 @@ -867,28 +877,39 @@
1.37 event_start = max(event_details["start"], start)
1.38 event_end = min(event_details["end"], end)
1.39 event_coverage = set(event_start.days_until(event_end))
1.40 + event_location = event_details.get("location")
1.41
1.42 # Update the overall coverage.
1.43
1.44 full_coverage.update(event_coverage)
1.45
1.46 - # Try and fit the event into the events list.
1.47 -
1.48 - for i, (coverage, covered_events) in enumerate(all_events):
1.49 -
1.50 - # Where the event does not overlap with the current
1.51 - # element, add it alongside existing events.
1.52 + # Add a new events list for a new location.
1.53 + # Locations can be unspecified, thus None refers to all unlocalised
1.54 + # events.
1.55
1.56 - if not coverage.intersection(event_coverage):
1.57 - covered_events.append(event)
1.58 - all_events[i] = coverage.union(event_coverage), covered_events
1.59 - break
1.60 + if not all_events.has_key(event_location):
1.61 + all_events[event_location] = [(event_coverage, [event])]
1.62
1.63 - # Make a new element in the list if the event cannot be
1.64 - # marked alongside existing events.
1.65 + # Try and fit the event into an events list.
1.66
1.67 else:
1.68 - all_events.append((event_coverage, [event]))
1.69 + slot = all_events[event_location]
1.70 +
1.71 + for i, (coverage, covered_events) in enumerate(slot):
1.72 +
1.73 + # Where the event does not overlap with the current
1.74 + # element, add it alongside existing events.
1.75 +
1.76 + if not coverage.intersection(event_coverage):
1.77 + covered_events.append(event)
1.78 + slot[i] = coverage.union(event_coverage), covered_events
1.79 + break
1.80 +
1.81 + # Make a new element in the list if the event cannot be
1.82 + # marked alongside existing events.
1.83 +
1.84 + else:
1.85 + slot.append((event_coverage, [event]))
1.86
1.87 return full_coverage, all_events
1.88
2.1 --- a/macros/EventAggregator.py Sun Aug 08 17:07:59 2010 +0200
2.2 +++ b/macros/EventAggregator.py Fri Oct 22 01:13:28 2010 +0200
2.3 @@ -623,7 +623,7 @@
2.4 week_start = month.as_date(max(first_day, 1))
2.5 week_end = month.as_date(min(first_day + 6, number_of_days))
2.6
2.7 - week_coverage, week_events = EventAggregatorSupport.getCoverage(
2.8 + full_coverage, week_slots = EventAggregatorSupport.getCoverage(
2.9 week_start, week_end, shown_events.get(month, []))
2.10
2.11 # Output a week, starting with the day numbers.
2.12 @@ -644,7 +644,7 @@
2.13 # Output normal days.
2.14
2.15 else:
2.16 - if date in week_coverage:
2.17 + if date in full_coverage:
2.18 output.append(fmt.table_cell(on=1,
2.19 attrs={"class" : "event-day-heading event-day-busy", "colspan" : "3"}))
2.20 else:
2.21 @@ -666,7 +666,7 @@
2.22
2.23 # Either generate empty days...
2.24
2.25 - if not week_events:
2.26 + if not week_slots:
2.27 output.append(fmt.table_row(on=1))
2.28
2.29 for weekday in range(0, 7):
2.30 @@ -690,228 +690,237 @@
2.31 # Or visit each set of scheduled events...
2.32
2.33 else:
2.34 - for coverage, events in week_events:
2.35 + locations = week_slots.keys()
2.36 + locations.sort(EventAggregatorSupport.sort_none_first)
2.37
2.38 - # Output each set.
2.39 -
2.40 - output.append(fmt.table_row(on=1))
2.41 + # Visit each slot corresponding to a location (or no location).
2.42
2.43 - # Then, output day details.
2.44 + for location in locations:
2.45 +
2.46 + # Visit each coverage span, presenting the events in the span.
2.47
2.48 - for weekday in range(0, 7):
2.49 - day = first_day + weekday
2.50 - date = month.as_date(day)
2.51 + for coverage, events in week_slots[location]:
2.52
2.53 - # Skip out-of-month days.
2.54 + # Output each set.
2.55
2.56 - if day < 1 or day > number_of_days:
2.57 - output.append(fmt.table_cell(on=1,
2.58 - attrs={"class" : "event-day-content event-day-excluded", "colspan" : "3"}))
2.59 - output.append(fmt.table_cell(on=0))
2.60 - continue
2.61 + output.append(fmt.table_row(on=1))
2.62
2.63 - # Output the day.
2.64 + # Then, output day details.
2.65
2.66 - if date not in coverage:
2.67 - output.append(fmt.table_cell(on=1,
2.68 - attrs={"class" : "event-day-content event-day-empty", "colspan" : "3"}))
2.69 -
2.70 - # Get event details for the current day.
2.71 + for weekday in range(0, 7):
2.72 + day = first_day + weekday
2.73 + date = month.as_date(day)
2.74
2.75 - for event in events:
2.76 - event_page = event.getPage()
2.77 - event_details = event.getDetails()
2.78 + # Skip out-of-month days.
2.79
2.80 - if not (event_details["start"] <= date <= event_details["end"]):
2.81 + if day < 1 or day > number_of_days:
2.82 + output.append(fmt.table_cell(on=1,
2.83 + attrs={"class" : "event-day-content event-day-excluded", "colspan" : "3"}))
2.84 + output.append(fmt.table_cell(on=0))
2.85 continue
2.86
2.87 - # Get basic properties of the event.
2.88 + # Output the day.
2.89 +
2.90 + if date not in coverage:
2.91 + output.append(fmt.table_cell(on=1,
2.92 + attrs={"class" : "event-day-content event-day-empty", "colspan" : "3"}))
2.93
2.94 - starts_today = event_details["start"] == date
2.95 - ends_today = event_details["end"] == date
2.96 - event_summary = event.getSummary(parent_name)
2.97 - is_ambiguous = event_details["start"].ambiguous() or event_details["end"].ambiguous()
2.98 + # Get event details for the current day.
2.99
2.100 - # Generate a colour for the event.
2.101 + for event in events:
2.102 + event_page = event.getPage()
2.103 + event_details = event.getDetails()
2.104
2.105 - bg = getColour(event_summary)
2.106 - fg = getBlackOrWhite(bg)
2.107 - style = ("background-color: rgb(%d, %d, %d); color: rgb(%d, %d, %d);" % (bg + fg))
2.108 + if not (event_details["start"] <= date <= event_details["end"]):
2.109 + continue
2.110
2.111 - # Determine if the event name should be shown.
2.112 + # Get basic properties of the event.
2.113
2.114 - start_of_period = starts_today or weekday == 0 or day == 1
2.115 + starts_today = event_details["start"] == date
2.116 + ends_today = event_details["end"] == date
2.117 + event_summary = event.getSummary(parent_name)
2.118 + is_ambiguous = event_details["start"].ambiguous() or event_details["end"].ambiguous()
2.119
2.120 - if name_usage == "daily" or start_of_period:
2.121 - hide_text = 0
2.122 - else:
2.123 - hide_text = 1
2.124 + # Generate a colour for the event.
2.125
2.126 - # Output start of day gap and determine whether
2.127 - # any event content should be explicitly output
2.128 - # for this day.
2.129 + bg = getColour(event_summary)
2.130 + fg = getBlackOrWhite(bg)
2.131 + style = ("background-color: rgb(%d, %d, %d); color: rgb(%d, %d, %d);" % (bg + fg))
2.132
2.133 - if starts_today:
2.134 + # Determine if the event name should be shown.
2.135
2.136 - # Single day events...
2.137 + start_of_period = starts_today or weekday == 0 or day == 1
2.138
2.139 - if ends_today:
2.140 - colspan = 3
2.141 - event_day_type = "event-day-single"
2.142 + if name_usage == "daily" or start_of_period:
2.143 + hide_text = 0
2.144 + else:
2.145 + hide_text = 1
2.146
2.147 - # Events starting today...
2.148 + # Output start of day gap and determine whether
2.149 + # any event content should be explicitly output
2.150 + # for this day.
2.151
2.152 - else:
2.153 - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-start-gap"}))
2.154 - output.append(fmt.table_cell(on=0))
2.155 + if starts_today:
2.156
2.157 - # Calculate the span of this cell.
2.158 - # Events whose names appear on every day...
2.159 + # Single day events...
2.160
2.161 - if name_usage == "daily":
2.162 - colspan = 2
2.163 - event_day_type = "event-day-starting"
2.164 + if ends_today:
2.165 + colspan = 3
2.166 + event_day_type = "event-day-single"
2.167
2.168 - # Events whose names appear once per week...
2.169 + # Events starting today...
2.170
2.171 else:
2.172 - if event_details["end"] <= week_end:
2.173 - event_length = event_details["end"].day() - day + 1
2.174 - colspan = (event_length - 2) * 3 + 4
2.175 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-start-gap"}))
2.176 + output.append(fmt.table_cell(on=0))
2.177 +
2.178 + # Calculate the span of this cell.
2.179 + # Events whose names appear on every day...
2.180 +
2.181 + if name_usage == "daily":
2.182 + colspan = 2
2.183 + event_day_type = "event-day-starting"
2.184 +
2.185 + # Events whose names appear once per week...
2.186 +
2.187 else:
2.188 - event_length = week_end.day() - day + 1
2.189 - colspan = (event_length - 1) * 3 + 2
2.190 + if event_details["end"] <= week_end:
2.191 + event_length = event_details["end"].day() - day + 1
2.192 + colspan = (event_length - 2) * 3 + 4
2.193 + else:
2.194 + event_length = week_end.day() - day + 1
2.195 + colspan = (event_length - 1) * 3 + 2
2.196
2.197 - event_day_type = "event-day-multiple"
2.198 + event_day_type = "event-day-multiple"
2.199 +
2.200 + # Events continuing from a previous week...
2.201
2.202 - # Events continuing from a previous week...
2.203 + elif start_of_period:
2.204
2.205 - elif start_of_period:
2.206 + # End of continuing event...
2.207
2.208 - # End of continuing event...
2.209 + if ends_today:
2.210 + colspan = 2
2.211 + event_day_type = "event-day-ending"
2.212 +
2.213 + # Events continuing for at least one more day...
2.214 +
2.215 + else:
2.216
2.217 - if ends_today:
2.218 - colspan = 2
2.219 - event_day_type = "event-day-ending"
2.220 + # Calculate the span of this cell.
2.221 + # Events whose names appear on every day...
2.222 +
2.223 + if name_usage == "daily":
2.224 + colspan = 3
2.225 + event_day_type = "event-day-full"
2.226 +
2.227 + # Events whose names appear once per week...
2.228
2.229 - # Events continuing for at least one more day...
2.230 -
2.231 - else:
2.232 + else:
2.233 + if event_details["end"] <= week_end:
2.234 + event_length = event_details["end"].day() - day + 1
2.235 + colspan = (event_length - 1) * 3 + 2
2.236 + else:
2.237 + event_length = week_end.day() - day + 1
2.238 + colspan = event_length * 3
2.239
2.240 - # Calculate the span of this cell.
2.241 - # Events whose names appear on every day...
2.242 + event_day_type = "event-day-multiple"
2.243 +
2.244 + # Continuing events whose names appear on every day...
2.245
2.246 - if name_usage == "daily":
2.247 + elif name_usage == "daily":
2.248 + if ends_today:
2.249 + colspan = 2
2.250 + event_day_type = "event-day-ending"
2.251 + else:
2.252 colspan = 3
2.253 event_day_type = "event-day-full"
2.254
2.255 - # Events whose names appear once per week...
2.256 + # Continuing events whose names appear once per week...
2.257 +
2.258 + else:
2.259 + colspan = None
2.260
2.261 - else:
2.262 - if event_details["end"] <= week_end:
2.263 - event_length = event_details["end"].day() - day + 1
2.264 - colspan = (event_length - 1) * 3 + 2
2.265 - else:
2.266 - event_length = week_end.day() - day + 1
2.267 - colspan = event_length * 3
2.268 + # Output the main content only if it is not
2.269 + # continuing from a previous day.
2.270
2.271 - event_day_type = "event-day-multiple"
2.272 + if colspan is not None:
2.273
2.274 - # Continuing events whose names appear on every day...
2.275 + # Colour the cell for continuing events.
2.276
2.277 - elif name_usage == "daily":
2.278 - if ends_today:
2.279 - colspan = 2
2.280 - event_day_type = "event-day-ending"
2.281 - else:
2.282 - colspan = 3
2.283 - event_day_type = "event-day-full"
2.284 -
2.285 - # Continuing events whose names appear once per week...
2.286 + attrs={
2.287 + "class" : "event-day-content event-day-busy %s" % event_day_type,
2.288 + "colspan" : str(colspan)
2.289 + }
2.290
2.291 - else:
2.292 - colspan = None
2.293 + if not (starts_today and ends_today):
2.294 + attrs["style"] = style
2.295
2.296 - # Output the main content only if it is not
2.297 - # continuing from a previous day.
2.298 + output.append(fmt.table_cell(on=1, attrs=attrs))
2.299
2.300 - if colspan is not None:
2.301 + # Output the event.
2.302
2.303 - # Colour the cell for continuing events.
2.304 + if starts_today and ends_today or not hide_text:
2.305
2.306 - attrs={
2.307 - "class" : "event-day-content event-day-busy %s" % event_day_type,
2.308 - "colspan" : str(colspan)
2.309 - }
2.310 + # The event box contains the summary, alongside
2.311 + # other elements.
2.312
2.313 - if not (starts_today and ends_today):
2.314 - attrs["style"] = style
2.315 + output.append(fmt.div(on=1, css_class="event-summary-box"))
2.316 + output.append(fmt.div(on=1, css_class="event-summary", style=style))
2.317
2.318 - output.append(fmt.table_cell(on=1, attrs=attrs))
2.319 -
2.320 - # Output the event.
2.321 + if is_ambiguous:
2.322 + output.append(fmt.icon("/!\\"))
2.323
2.324 - if starts_today and ends_today or not hide_text:
2.325 -
2.326 - # The event box contains the summary, alongside
2.327 - # other elements.
2.328 + output.append(event_page.linkToPage(request, event_summary))
2.329 + output.append(fmt.div(on=0))
2.330
2.331 - output.append(fmt.div(on=1, css_class="event-summary-box"))
2.332 - output.append(fmt.div(on=1, css_class="event-summary", style=style))
2.333 + # Add a pop-up element for long summaries.
2.334
2.335 - if is_ambiguous:
2.336 - output.append(fmt.icon("/!\\"))
2.337 + output.append(fmt.div(on=1, css_class="event-summary-popup", style=style))
2.338
2.339 - output.append(event_page.linkToPage(request, event_summary))
2.340 - output.append(fmt.div(on=0))
2.341 + if is_ambiguous:
2.342 + output.append(fmt.icon("/!\\"))
2.343
2.344 - # Add a pop-up element for long summaries.
2.345 -
2.346 - output.append(fmt.div(on=1, css_class="event-summary-popup", style=style))
2.347 + output.append(event_page.linkToPage(request, event_summary))
2.348 + output.append(fmt.div(on=0))
2.349
2.350 - if is_ambiguous:
2.351 - output.append(fmt.icon("/!\\"))
2.352 + output.append(fmt.div(on=0))
2.353
2.354 - output.append(event_page.linkToPage(request, event_summary))
2.355 - output.append(fmt.div(on=0))
2.356 + # Output end of day content.
2.357
2.358 output.append(fmt.div(on=0))
2.359
2.360 - # Output end of day content.
2.361 + # Output end of day gap.
2.362
2.363 - output.append(fmt.div(on=0))
2.364 + if ends_today and not starts_today:
2.365 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-end-gap"}))
2.366 + output.append(fmt.table_cell(on=0))
2.367
2.368 - # Output end of day gap.
2.369 + # End of day.
2.370
2.371 - if ends_today and not starts_today:
2.372 - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-end-gap"}))
2.373 - output.append(fmt.table_cell(on=0))
2.374 + output.append(fmt.table_cell(on=0))
2.375
2.376 - # End of day.
2.377 + # End of set.
2.378
2.379 - output.append(fmt.table_cell(on=0))
2.380 + output.append(fmt.table_row(on=0))
2.381
2.382 - # End of set.
2.383 -
2.384 - output.append(fmt.table_row(on=0))
2.385 + # Add a spacer.
2.386
2.387 - # Add a spacer.
2.388 -
2.389 - output.append(fmt.table_row(on=1))
2.390 + output.append(fmt.table_row(on=1))
2.391
2.392 - for weekday in range(0, 7):
2.393 - day = first_day + weekday
2.394 - css_classes = "event-day-spacer"
2.395 + for weekday in range(0, 7):
2.396 + day = first_day + weekday
2.397 + css_classes = "event-day-spacer"
2.398 +
2.399 + # Skip out-of-month days.
2.400
2.401 - # Skip out-of-month days.
2.402 -
2.403 - if day < 1 or day > number_of_days:
2.404 - css_classes += " event-day-excluded"
2.405 + if day < 1 or day > number_of_days:
2.406 + css_classes += " event-day-excluded"
2.407
2.408 - output.append(fmt.table_cell(on=1, attrs={"class" : css_classes, "colspan" : "3"}))
2.409 - output.append(fmt.table_cell(on=0))
2.410 + output.append(fmt.table_cell(on=1, attrs={"class" : css_classes, "colspan" : "3"}))
2.411 + output.append(fmt.table_cell(on=0))
2.412
2.413 - output.append(fmt.table_row(on=0))
2.414 + output.append(fmt.table_row(on=0))
2.415
2.416 # Process the next week...
2.417