# HG changeset patch # User Paul Boddie # Date 1287790547 -7200 # Node ID 3d6157e1fa9485c956a43eab26c229143418dd52 # Parent 58a87eeed458f5616fc44697f817b98f1e8687cd Moved various calendar presentation code regions into the View class as distinct methods. diff -r 58a87eeed458 -r 3d6157e1fa94 macros/EventAggregator.py --- a/macros/EventAggregator.py Fri Oct 22 22:06:18 2010 +0200 +++ b/macros/EventAggregator.py Sat Oct 23 01:35:47 2010 +0200 @@ -24,7 +24,7 @@ def __init__(self, page, calendar_name, raw_calendar_start, raw_calendar_end, calendar_start, calendar_end, first, last, category_names, template_name, - parent_name, mode): + parent_name, mode, name_usage): """ Initialise the view with the current 'page', a 'calendar_name' (which @@ -35,6 +35,9 @@ The additional 'category_names', 'template_name', 'parent_name' and 'mode' parameters are used to configure the links employed by the view. + + The 'name_usage' parameter controls how names are shown on calendar mode + events. """ self.page = page @@ -46,6 +49,7 @@ self.template_name = template_name self.parent_name = parent_name self.mode = mode + self.name_usage = name_usage self.category_name_parameters = "&".join([("category=%s" % name) for name in category_names]) @@ -375,6 +379,330 @@ return "".join(output) + # Calendar layout methods. + + def writeDayNumbers(self, first_day, number_of_days, month, busy_dates): + page = self.page + fmt = page.formatter + + output = [] + output.append(fmt.table_row(on=1)) + + for weekday in range(0, 7): + day = first_day + weekday + date = month.as_date(day) + + # Output out-of-month days. + + if day < 1 or day > number_of_days: + output.append(fmt.table_cell(on=1, + attrs={"class" : "event-day-heading event-day-excluded", "colspan" : "3"})) + output.append(fmt.table_cell(on=0)) + + # Output normal days. + + else: + if date in busy_dates: + output.append(fmt.table_cell(on=1, + attrs={"class" : "event-day-heading event-day-busy", "colspan" : "3"})) + else: + output.append(fmt.table_cell(on=1, + attrs={"class" : "event-day-heading event-day-empty", "colspan" : "3"})) + + # Output the day number, making a link to a new event + # action. + + output.append(self.writeDayNumberLinked(date)) + + # End of day. + + output.append(fmt.table_cell(on=0)) + + # End of day numbers. + + output.append(fmt.table_row(on=0)) + return "".join(output) + + def writeEmptyWeek(self, first_day, number_of_days): + page = self.page + fmt = page.formatter + + output = [] + output.append(fmt.table_row(on=1)) + + for weekday in range(0, 7): + day = first_day + weekday + + # Output out-of-month days. + + 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)) + + # Output empty days. + + else: + output.append(fmt.table_cell(on=1, + attrs={"class" : "event-day-content event-day-empty", "colspan" : "3"})) + + output.append(fmt.table_row(on=0)) + return "".join(output) + + def writeWeekSlots(self, first_day, number_of_days, month, week_end, week_slots): + output = [] + + locations = week_slots.keys() + locations.sort(EventAggregatorSupport.sort_none_first) + + # Visit each slot corresponding to a location (or no location). + + for location in locations: + + # Visit each coverage span, presenting the events in the span. + + for coverage, events in week_slots[location]: + + # Output each set. + + output.append(self.writeWeekSlot(first_day, number_of_days, month, week_end, coverage, events)) + + # Add a spacer. + + output.append(self.writeSpacer(first_day, number_of_days)) + + return "".join(output) + + def writeWeekSlot(self, first_day, number_of_days, month, week_end, coverage, events): + page = self.page + request = page.request + fmt = page.formatter + + output = [] + output.append(fmt.table_row(on=1)) + + # Then, output day details. + + for weekday in range(0, 7): + day = first_day + weekday + date = month.as_date(day) + + # Skip out-of-month days. + + 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 the day. + + 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 event in events: + event_page = event.getPage() + event_details = event.getDetails() + + if not (event_details["start"] <= date <= event_details["end"]): + continue + + # Get basic properties of the event. + + starts_today = event_details["start"] == date + ends_today = event_details["end"] == date + event_summary = event.getSummary(self.parent_name) + is_ambiguous = event_details["start"].ambiguous() or event_details["end"].ambiguous() + + # Generate a colour for the event. + + bg = getColour(event_summary) + fg = getBlackOrWhite(bg) + style = ("background-color: rgb(%d, %d, %d); color: rgb(%d, %d, %d);" % (bg + fg)) + + # Determine if the event name should be shown. + + start_of_period = starts_today or weekday == 0 or day == 1 + + if self.name_usage == "daily" or start_of_period: + hide_text = 0 + else: + hide_text = 1 + + # Output start of day gap and determine whether + # any event content should be explicitly output + # for this day. + + if starts_today: + + # Single day events... + + if ends_today: + colspan = 3 + event_day_type = "event-day-single" + + # Events starting today... + + else: + 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 self.name_usage == "daily": + colspan = 2 + event_day_type = "event-day-starting" + + # Events whose names appear once per week... + + else: + 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" + + # Events continuing from a previous week... + + elif start_of_period: + + # End of continuing event... + + if ends_today: + colspan = 2 + event_day_type = "event-day-ending" + + # Events continuing for at least one more day... + + else: + + # Calculate the span of this cell. + # Events whose names appear on every day... + + if self.name_usage == "daily": + colspan = 3 + event_day_type = "event-day-full" + + # Events whose names appear once per week... + + 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 + + event_day_type = "event-day-multiple" + + # Continuing events whose names appear on every day... + + elif self.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... + + else: + colspan = None + + # Output the main content only if it is not + # continuing from a previous day. + + if colspan is not None: + + # Colour the cell for continuing events. + + attrs={ + "class" : "event-day-content event-day-busy %s" % event_day_type, + "colspan" : str(colspan) + } + + if not (starts_today and ends_today): + attrs["style"] = style + + output.append(fmt.table_cell(on=1, attrs=attrs)) + + # Output the event. + + if starts_today and ends_today or not hide_text: + + # The event box contains the summary, alongside + # other elements. + + output.append(fmt.div(on=1, css_class="event-summary-box")) + output.append(fmt.div(on=1, css_class="event-summary", style=style)) + + if is_ambiguous: + output.append(fmt.icon("/!\\")) + + output.append(event_page.linkToPage(request, event_summary)) + output.append(fmt.div(on=0)) + + # Add a pop-up element for long summaries. + + output.append(fmt.div(on=1, css_class="event-summary-popup", style=style)) + + if is_ambiguous: + output.append(fmt.icon("/!\\")) + + output.append(event_page.linkToPage(request, event_summary)) + output.append(fmt.div(on=0)) + + output.append(fmt.div(on=0)) + + # Output end of day content. + + output.append(fmt.div(on=0)) + + # Output end of day gap. + + 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)) + + # End of day. + + output.append(fmt.table_cell(on=0)) + + # End of set. + + output.append(fmt.table_row(on=0)) + return "".join(output) + + def writeSpacer(self, first_day, number_of_days): + page = self.page + fmt = page.formatter + + output = [] + output.append(fmt.table_row(on=1)) + + for weekday in range(0, 7): + day = first_day + weekday + css_classes = "event-day-spacer" + + # Skip out-of-month days. + + 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_row(on=0)) + return "".join(output) + # HTML-related functions. def getColour(s): @@ -498,7 +826,7 @@ # Define a view of the calendar, retaining useful navigational information. view = View(page, calendar_name, raw_calendar_start, raw_calendar_end, calendar_start, calendar_end, - first, last, category_names, template_name, parent_name, mode) + first, last, category_names, template_name, parent_name, mode, name_usage) # Make a calendar. @@ -660,299 +988,17 @@ # Output a week, starting with the day numbers. - output.append(fmt.table_row(on=1)) - - for weekday in range(0, 7): - day = first_day + weekday - date = month.as_date(day) - - # Output out-of-month days. - - if day < 1 or day > number_of_days: - output.append(fmt.table_cell(on=1, - attrs={"class" : "event-day-heading event-day-excluded", "colspan" : "3"})) - output.append(fmt.table_cell(on=0)) - - # Output normal days. - - else: - if date in full_coverage: - output.append(fmt.table_cell(on=1, - attrs={"class" : "event-day-heading event-day-busy", "colspan" : "3"})) - else: - output.append(fmt.table_cell(on=1, - attrs={"class" : "event-day-heading event-day-empty", "colspan" : "3"})) - - # Output the day number, making a link to a new event - # action. - - output.append(view.writeDayNumberLinked(date)) - - # End of day. - - output.append(fmt.table_cell(on=0)) - - # End of day numbers. - - output.append(fmt.table_row(on=0)) + output.append(view.writeDayNumbers(first_day, number_of_days, month, full_coverage)) # Either generate empty days... if not week_slots: - output.append(fmt.table_row(on=1)) - - for weekday in range(0, 7): - day = first_day + weekday - - # Output out-of-month days. + output.append(view.writeEmptyWeek(first_day, number_of_days)) - 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)) - - # Output empty days. - - else: - output.append(fmt.table_cell(on=1, - attrs={"class" : "event-day-content event-day-empty", "colspan" : "3"})) - - output.append(fmt.table_row(on=0)) - - # Or visit each set of scheduled events... + # Or generate each set of scheduled events... else: - locations = week_slots.keys() - locations.sort(EventAggregatorSupport.sort_none_first) - - # Visit each slot corresponding to a location (or no location). - - for location in locations: - - # Visit each coverage span, presenting the events in the span. - - for coverage, events in week_slots[location]: - - # Output each set. - - output.append(fmt.table_row(on=1)) - - # Then, output day details. - - for weekday in range(0, 7): - day = first_day + weekday - date = month.as_date(day) - - # Skip out-of-month days. - - 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 the day. - - 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 event in events: - event_page = event.getPage() - event_details = event.getDetails() - - if not (event_details["start"] <= date <= event_details["end"]): - continue - - # Get basic properties of the event. - - 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() - - # Generate a colour for the event. - - bg = getColour(event_summary) - fg = getBlackOrWhite(bg) - style = ("background-color: rgb(%d, %d, %d); color: rgb(%d, %d, %d);" % (bg + fg)) - - # Determine if the event name should be shown. - - start_of_period = starts_today or weekday == 0 or day == 1 - - if name_usage == "daily" or start_of_period: - hide_text = 0 - else: - hide_text = 1 - - # Output start of day gap and determine whether - # any event content should be explicitly output - # for this day. - - if starts_today: - - # Single day events... - - if ends_today: - colspan = 3 - event_day_type = "event-day-single" - - # Events starting today... - - else: - 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: - 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" - - # Events continuing from a previous week... - - elif start_of_period: - - # End of continuing event... - - if ends_today: - colspan = 2 - event_day_type = "event-day-ending" - - # Events continuing for at least one more day... - - else: - - # 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... - - 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 - - event_day_type = "event-day-multiple" - - # Continuing events whose names appear on every day... - - 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... - - else: - colspan = None - - # Output the main content only if it is not - # continuing from a previous day. - - if colspan is not None: - - # Colour the cell for continuing events. - - attrs={ - "class" : "event-day-content event-day-busy %s" % event_day_type, - "colspan" : str(colspan) - } - - if not (starts_today and ends_today): - attrs["style"] = style - - output.append(fmt.table_cell(on=1, attrs=attrs)) - - # Output the event. - - if starts_today and ends_today or not hide_text: - - # The event box contains the summary, alongside - # other elements. - - output.append(fmt.div(on=1, css_class="event-summary-box")) - output.append(fmt.div(on=1, css_class="event-summary", style=style)) - - if is_ambiguous: - output.append(fmt.icon("/!\\")) - - output.append(event_page.linkToPage(request, event_summary)) - output.append(fmt.div(on=0)) - - # Add a pop-up element for long summaries. - - output.append(fmt.div(on=1, css_class="event-summary-popup", style=style)) - - if is_ambiguous: - output.append(fmt.icon("/!\\")) - - output.append(event_page.linkToPage(request, event_summary)) - output.append(fmt.div(on=0)) - - output.append(fmt.div(on=0)) - - # Output end of day content. - - output.append(fmt.div(on=0)) - - # Output end of day gap. - - 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)) - - # End of day. - - output.append(fmt.table_cell(on=0)) - - # End of set. - - output.append(fmt.table_row(on=0)) - - # Add a spacer. - - output.append(fmt.table_row(on=1)) - - for weekday in range(0, 7): - day = first_day + weekday - css_classes = "event-day-spacer" - - # Skip out-of-month days. - - 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_row(on=0)) + output.append(view.writeWeekSlots(first_day, number_of_days, month, week_end, week_slots)) # Process the next week...