# HG changeset patch # User Paul Boddie # Date 1287702808 -7200 # Node ID 844790c570981ddd08f25af0c49e37db9be091a6 # Parent f58f23315d69ba19c96a309e1ca92bad0be4889a Changed the event coverage to be a tuple with the merged coverage of events regardless of location together with a dictionary mapping locations to (coverage, event list) tuples. diff -r f58f23315d69 -r 844790c57098 EventAggregatorSupport.py --- a/EventAggregatorSupport.py Sun Aug 08 17:07:59 2010 +0200 +++ b/EventAggregatorSupport.py Fri Oct 22 01:13:28 2010 +0200 @@ -94,6 +94,14 @@ else: return int(x) +def sort_none_first(x, y): + if x is None: + return -1 + elif y is None: + return 1 + else: + return cmp(x, y) + # Utility classes and associated functions. class Form: @@ -841,6 +849,8 @@ return min(first, last), last +# NOTE: Support coverage using times within days. + def getCoverage(start, end, events): """ @@ -850,7 +860,7 @@ of the form (set of covered days, events). """ - all_events = [] + all_events = {} full_coverage = set() # Get event details. @@ -867,28 +877,39 @@ event_start = max(event_details["start"], start) event_end = min(event_details["end"], end) event_coverage = set(event_start.days_until(event_end)) + event_location = event_details.get("location") # Update the overall coverage. full_coverage.update(event_coverage) - # Try and fit the event into the events list. - - for i, (coverage, covered_events) in enumerate(all_events): - - # Where the event does not overlap with the current - # element, add it alongside existing events. + # Add a new events list for a new location. + # Locations can be unspecified, thus None refers to all unlocalised + # events. - if not coverage.intersection(event_coverage): - covered_events.append(event) - all_events[i] = coverage.union(event_coverage), covered_events - break + if not all_events.has_key(event_location): + all_events[event_location] = [(event_coverage, [event])] - # Make a new element in the list if the event cannot be - # marked alongside existing events. + # Try and fit the event into an events list. else: - all_events.append((event_coverage, [event])) + slot = all_events[event_location] + + for i, (coverage, covered_events) in enumerate(slot): + + # Where the event does not overlap with the current + # element, add it alongside existing events. + + if not coverage.intersection(event_coverage): + covered_events.append(event) + slot[i] = coverage.union(event_coverage), covered_events + break + + # Make a new element in the list if the event cannot be + # marked alongside existing events. + + else: + slot.append((event_coverage, [event])) return full_coverage, all_events diff -r f58f23315d69 -r 844790c57098 macros/EventAggregator.py --- a/macros/EventAggregator.py Sun Aug 08 17:07:59 2010 +0200 +++ b/macros/EventAggregator.py Fri Oct 22 01:13:28 2010 +0200 @@ -623,7 +623,7 @@ week_start = month.as_date(max(first_day, 1)) week_end = month.as_date(min(first_day + 6, number_of_days)) - week_coverage, week_events = EventAggregatorSupport.getCoverage( + full_coverage, week_slots = EventAggregatorSupport.getCoverage( week_start, week_end, shown_events.get(month, [])) # Output a week, starting with the day numbers. @@ -644,7 +644,7 @@ # Output normal days. else: - if date in week_coverage: + if date in full_coverage: output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading event-day-busy", "colspan" : "3"})) else: @@ -666,7 +666,7 @@ # Either generate empty days... - if not week_events: + if not week_slots: output.append(fmt.table_row(on=1)) for weekday in range(0, 7): @@ -690,228 +690,237 @@ # Or visit each set of scheduled events... else: - for coverage, events in week_events: + locations = week_slots.keys() + locations.sort(EventAggregatorSupport.sort_none_first) - # Output each set. - - output.append(fmt.table_row(on=1)) + # Visit each slot corresponding to a location (or no location). - # Then, output day details. + for location in locations: + + # Visit each coverage span, presenting the events in the span. - for weekday in range(0, 7): - day = first_day + weekday - date = month.as_date(day) + for coverage, events in week_slots[location]: - # Skip out-of-month days. + # Output each set. - if day < 1 or day > number_of_days: - output.append(fmt.table_cell(on=1, - attrs={"class" : "event-day-content event-day-excluded", "colspan" : "3"})) - output.append(fmt.table_cell(on=0)) - continue + output.append(fmt.table_row(on=1)) - # Output the day. + # Then, output day details. - if date not in coverage: - output.append(fmt.table_cell(on=1, - attrs={"class" : "event-day-content event-day-empty", "colspan" : "3"})) - - # Get event details for the current day. + for weekday in range(0, 7): + day = first_day + weekday + date = month.as_date(day) - for event in events: - event_page = event.getPage() - event_details = event.getDetails() + # Skip out-of-month days. - if not (event_details["start"] <= date <= event_details["end"]): + if day < 1 or day > number_of_days: + output.append(fmt.table_cell(on=1, + attrs={"class" : "event-day-content event-day-excluded", "colspan" : "3"})) + output.append(fmt.table_cell(on=0)) continue - # Get basic properties of the event. + # Output the day. + + if date not in coverage: + output.append(fmt.table_cell(on=1, + attrs={"class" : "event-day-content event-day-empty", "colspan" : "3"})) - starts_today = event_details["start"] == date - ends_today = event_details["end"] == date - event_summary = event.getSummary(parent_name) - is_ambiguous = event_details["start"].ambiguous() or event_details["end"].ambiguous() + # Get event details for the current day. - # Generate a colour for the event. + for event in events: + event_page = event.getPage() + event_details = event.getDetails() - bg = getColour(event_summary) - fg = getBlackOrWhite(bg) - style = ("background-color: rgb(%d, %d, %d); color: rgb(%d, %d, %d);" % (bg + fg)) + if not (event_details["start"] <= date <= event_details["end"]): + continue - # Determine if the event name should be shown. + # Get basic properties of the event. - start_of_period = starts_today or weekday == 0 or day == 1 + starts_today = event_details["start"] == date + ends_today = event_details["end"] == date + event_summary = event.getSummary(parent_name) + is_ambiguous = event_details["start"].ambiguous() or event_details["end"].ambiguous() - if name_usage == "daily" or start_of_period: - hide_text = 0 - else: - hide_text = 1 + # Generate a colour for the event. - # Output start of day gap and determine whether - # any event content should be explicitly output - # for this day. + bg = getColour(event_summary) + fg = getBlackOrWhite(bg) + style = ("background-color: rgb(%d, %d, %d); color: rgb(%d, %d, %d);" % (bg + fg)) - if starts_today: + # Determine if the event name should be shown. - # Single day events... + start_of_period = starts_today or weekday == 0 or day == 1 - if ends_today: - colspan = 3 - event_day_type = "event-day-single" + if name_usage == "daily" or start_of_period: + hide_text = 0 + else: + hide_text = 1 - # Events starting today... + # Output start of day gap and determine whether + # any event content should be explicitly output + # for this day. - else: - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-start-gap"})) - output.append(fmt.table_cell(on=0)) + if starts_today: - # Calculate the span of this cell. - # Events whose names appear on every day... + # Single day events... - if name_usage == "daily": - colspan = 2 - event_day_type = "event-day-starting" + if ends_today: + colspan = 3 + event_day_type = "event-day-single" - # Events whose names appear once per week... + # Events starting today... else: - if event_details["end"] <= week_end: - event_length = event_details["end"].day() - day + 1 - colspan = (event_length - 2) * 3 + 4 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-start-gap"})) + output.append(fmt.table_cell(on=0)) + + # Calculate the span of this cell. + # Events whose names appear on every day... + + if name_usage == "daily": + colspan = 2 + event_day_type = "event-day-starting" + + # Events whose names appear once per week... + else: - event_length = week_end.day() - day + 1 - colspan = (event_length - 1) * 3 + 2 + if event_details["end"] <= week_end: + event_length = event_details["end"].day() - day + 1 + colspan = (event_length - 2) * 3 + 4 + else: + event_length = week_end.day() - day + 1 + colspan = (event_length - 1) * 3 + 2 - event_day_type = "event-day-multiple" + event_day_type = "event-day-multiple" + + # Events continuing from a previous week... - # Events continuing from a previous week... + elif start_of_period: - elif start_of_period: + # End of continuing event... - # End of continuing event... + if ends_today: + colspan = 2 + event_day_type = "event-day-ending" + + # Events continuing for at least one more day... + + else: - if ends_today: - colspan = 2 - event_day_type = "event-day-ending" + # Calculate the span of this cell. + # Events whose names appear on every day... + + if name_usage == "daily": + colspan = 3 + event_day_type = "event-day-full" + + # Events whose names appear once per week... - # Events continuing for at least one more day... - - else: + else: + if event_details["end"] <= week_end: + event_length = event_details["end"].day() - day + 1 + colspan = (event_length - 1) * 3 + 2 + else: + event_length = week_end.day() - day + 1 + colspan = event_length * 3 - # Calculate the span of this cell. - # Events whose names appear on every day... + event_day_type = "event-day-multiple" + + # Continuing events whose names appear on every day... - if name_usage == "daily": + elif name_usage == "daily": + if ends_today: + colspan = 2 + event_day_type = "event-day-ending" + else: colspan = 3 event_day_type = "event-day-full" - # Events whose names appear once per week... + # Continuing events whose names appear once per week... + + else: + colspan = None - else: - if event_details["end"] <= week_end: - event_length = event_details["end"].day() - day + 1 - colspan = (event_length - 1) * 3 + 2 - else: - event_length = week_end.day() - day + 1 - colspan = event_length * 3 + # Output the main content only if it is not + # continuing from a previous day. - event_day_type = "event-day-multiple" + if colspan is not None: - # Continuing events whose names appear on every day... + # Colour the cell for continuing events. - elif name_usage == "daily": - if ends_today: - colspan = 2 - event_day_type = "event-day-ending" - else: - colspan = 3 - event_day_type = "event-day-full" - - # Continuing events whose names appear once per week... + attrs={ + "class" : "event-day-content event-day-busy %s" % event_day_type, + "colspan" : str(colspan) + } - else: - colspan = None + if not (starts_today and ends_today): + attrs["style"] = style - # Output the main content only if it is not - # continuing from a previous day. + output.append(fmt.table_cell(on=1, attrs=attrs)) - if colspan is not None: + # Output the event. - # Colour the cell for continuing events. + if starts_today and ends_today or not hide_text: - attrs={ - "class" : "event-day-content event-day-busy %s" % event_day_type, - "colspan" : str(colspan) - } + # The event box contains the summary, alongside + # other elements. - if not (starts_today and ends_today): - attrs["style"] = style + output.append(fmt.div(on=1, css_class="event-summary-box")) + output.append(fmt.div(on=1, css_class="event-summary", style=style)) - output.append(fmt.table_cell(on=1, attrs=attrs)) - - # Output the event. + if is_ambiguous: + output.append(fmt.icon("/!\\")) - if starts_today and ends_today or not hide_text: - - # The event box contains the summary, alongside - # other elements. + output.append(event_page.linkToPage(request, event_summary)) + output.append(fmt.div(on=0)) - output.append(fmt.div(on=1, css_class="event-summary-box")) - output.append(fmt.div(on=1, css_class="event-summary", style=style)) + # Add a pop-up element for long summaries. - if is_ambiguous: - output.append(fmt.icon("/!\\")) + output.append(fmt.div(on=1, css_class="event-summary-popup", style=style)) - output.append(event_page.linkToPage(request, event_summary)) - output.append(fmt.div(on=0)) + if is_ambiguous: + output.append(fmt.icon("/!\\")) - # Add a pop-up element for long summaries. - - output.append(fmt.div(on=1, css_class="event-summary-popup", style=style)) + output.append(event_page.linkToPage(request, event_summary)) + output.append(fmt.div(on=0)) - if is_ambiguous: - output.append(fmt.icon("/!\\")) + output.append(fmt.div(on=0)) - output.append(event_page.linkToPage(request, event_summary)) - output.append(fmt.div(on=0)) + # Output end of day content. output.append(fmt.div(on=0)) - # Output end of day content. + # Output end of day gap. - output.append(fmt.div(on=0)) + if ends_today and not starts_today: + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-end-gap"})) + output.append(fmt.table_cell(on=0)) - # Output end of day gap. + # End of day. - if ends_today and not starts_today: - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-end-gap"})) - output.append(fmt.table_cell(on=0)) + output.append(fmt.table_cell(on=0)) - # End of day. + # End of set. - output.append(fmt.table_cell(on=0)) + output.append(fmt.table_row(on=0)) - # End of set. - - output.append(fmt.table_row(on=0)) + # Add a spacer. - # Add a spacer. - - output.append(fmt.table_row(on=1)) + output.append(fmt.table_row(on=1)) - for weekday in range(0, 7): - day = first_day + weekday - css_classes = "event-day-spacer" + for weekday in range(0, 7): + day = first_day + weekday + css_classes = "event-day-spacer" + + # Skip out-of-month days. - # Skip out-of-month days. - - if day < 1 or day > number_of_days: - css_classes += " event-day-excluded" + if day < 1 or day > number_of_days: + css_classes += " event-day-excluded" - output.append(fmt.table_cell(on=1, attrs={"class" : css_classes, "colspan" : "3"})) - output.append(fmt.table_cell(on=0)) + output.append(fmt.table_cell(on=1, attrs={"class" : css_classes, "colspan" : "3"})) + output.append(fmt.table_cell(on=0)) - output.append(fmt.table_row(on=0)) + output.append(fmt.table_row(on=0)) # Process the next week...