1.1 --- a/macros/EventAggregator.py Sun Mar 22 02:25:49 2009 +0100
1.2 +++ b/macros/EventAggregator.py Sun Mar 22 21:34:04 2009 +0100
1.3 @@ -13,6 +13,11 @@
1.4 import calendar
1.5 import re
1.6
1.7 +try:
1.8 + set
1.9 +except NameError:
1.10 + from sets import Set as set
1.11 +
1.12 __version__ = "0.1"
1.13
1.14 Dependencies = ['pages']
1.15 @@ -111,24 +116,40 @@
1.16 else:
1.17 return None
1.18
1.19 -def monthrange(first, last):
1.20 +def daterange(first, last):
1.21 results = []
1.22
1.23 + months_only = len(first) == 2
1.24 + start_year = first[0]
1.25 end_year = last[0]
1.26
1.27 - for year in range(first[0], end_year + 1):
1.28 - if year < last[0]:
1.29 + for year in range(start_year, end_year + 1):
1.30 + if year < end_year:
1.31 end_month = 12
1.32 else:
1.33 end_month = last[1]
1.34
1.35 - if year > first[0]:
1.36 + if year > start_year:
1.37 start_month = 1
1.38 else:
1.39 start_month = first[1]
1.40
1.41 for month in range(start_month, end_month + 1):
1.42 - results.append((year, month))
1.43 + if months_only:
1.44 + results.append((year, month))
1.45 + else:
1.46 + if month < end_month:
1.47 + _wd, end_day = calendar.monthrange(year, month)
1.48 + else:
1.49 + end_day = last[2]
1.50 +
1.51 + if month > start_month:
1.52 + start_day = 1
1.53 + else:
1.54 + start_day = first[2]
1.55 +
1.56 + for day in range(start_day, end_day + 1):
1.57 + results.append((year, month, day))
1.58
1.59 return results
1.60
1.61 @@ -153,9 +174,16 @@
1.62 """
1.63 Execute the 'macro' with the given 'args': an optional list of selected
1.64 category names (categories whose pages are to be shown), together with
1.65 - optional named arguments of the form "start=YYYY-MM" and "end=YYYY-MM"
1.66 - (indicating a restricted view of all events), and "mode=list" or
1.67 - "mode=calendar" (indicating the style of view).
1.68 + optional named arguments of the following forms:
1.69 +
1.70 + start=YYYY-MM shows event details starting from the specified month
1.71 + end=YYYY-MM shows event details ending at the specified month
1.72 +
1.73 + mode=calendar shows a calendar view of events
1.74 + mode=list shows a list of events by month
1.75 +
1.76 + names=daily shows the name of an event on every day of that event
1.77 + names=weekly shows the name of an event once per week
1.78 """
1.79
1.80 request = macro.request
1.81 @@ -178,6 +206,7 @@
1.82 calendar_start = None
1.83 calendar_end = None
1.84 mode = "calendar"
1.85 + name_usage = "daily"
1.86
1.87 for arg in parsed_args:
1.88 if arg.startswith("start="):
1.89 @@ -186,6 +215,8 @@
1.90 calendar_end = getMonth(arg[4:])
1.91 elif arg.startswith("mode="):
1.92 mode = arg[5:]
1.93 + elif arg.startswith("names="):
1.94 + name_usage = arg[6:]
1.95 else:
1.96 category_names.append(arg)
1.97
1.98 @@ -213,6 +244,9 @@
1.99
1.100 real_page_in_category = Page(request, pagename)
1.101 event_details = getEventDetails(real_page_in_category)
1.102 +
1.103 + # Define the event as the page together with its details.
1.104 +
1.105 event = (real_page_in_category, event_details)
1.106 events.append(event)
1.107
1.108 @@ -239,7 +273,7 @@
1.109 first = max(start_month, calendar_start or start_month)
1.110 last = min(end_month, calendar_end or end_month)
1.111
1.112 - for event_month in monthrange(first, last):
1.113 + for event_month in daterange(first, last):
1.114 if not shown_events.has_key(event_month):
1.115 shown_events[event_month] = []
1.116 shown_events[event_month].append(event)
1.117 @@ -256,7 +290,7 @@
1.118 first = calendar_start or earliest
1.119 last = calendar_end or latest
1.120
1.121 - for year, month in monthrange(first, last):
1.122 + for year, month in daterange(first, last):
1.123
1.124 # Either output a calendar view...
1.125
1.126 @@ -283,7 +317,7 @@
1.127 output.append(fmt.table_row(on=1))
1.128
1.129 for weekday in range(0, 7):
1.130 - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading"}))
1.131 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-weekday-heading"}))
1.132 output.append(fmt.text(_(weekday_labels[weekday])))
1.133 output.append(fmt.table_cell(on=0))
1.134
1.135 @@ -302,41 +336,73 @@
1.136
1.137 while first_day <= number_of_days:
1.138
1.139 - # Output a week.
1.140 + # Find events in this week and determine how to mark them on the
1.141 + # calendar.
1.142 +
1.143 + week_events = []
1.144 + week_coverage = set()
1.145 +
1.146 + week_start = (year, month, max(first_day, 1))
1.147 + week_end = (year, month, min(first_day + 6, number_of_days))
1.148 +
1.149 + # Get event details.
1.150 +
1.151 + for event in shown_events.get((year, month), []):
1.152 + event_page, event_details = event
1.153 +
1.154 + # Test for the event in the current week.
1.155 +
1.156 + if event_details["start"] <= week_end and event_details["end"] >= week_start:
1.157 +
1.158 + # Find the coverage of this week for the event.
1.159 +
1.160 + event_start = max(event_details["start"], week_start)
1.161 + event_end = min(event_details["end"], week_end)
1.162 + event_coverage = set(daterange(event_start, event_end))
1.163 +
1.164 + # Update the overall coverage.
1.165 +
1.166 + week_coverage.update(event_coverage)
1.167 +
1.168 + # Try and fit the event into the events list.
1.169 +
1.170 + for i, (coverage, events) in enumerate(week_events):
1.171 +
1.172 + # Where the event does not overlap with the current
1.173 + # element, add it alongside existing events.
1.174 +
1.175 + if not coverage.intersection(event_coverage):
1.176 + events.append(event)
1.177 + week_events[i] = coverage.union(event_coverage), events
1.178 + break
1.179 +
1.180 + # Make a new element in the list if the event cannot be
1.181 + # marked alongside existing events.
1.182 +
1.183 + else:
1.184 + week_events.append((event_coverage, [event]))
1.185 +
1.186 + # Output a week, starting with the day numbers.
1.187
1.188 output.append(fmt.table_row(on=1))
1.189
1.190 for weekday in range(0, 7):
1.191 day = first_day + weekday
1.192 + date = (year, month, day)
1.193
1.194 # Output out-of-month days.
1.195
1.196 if day < 1 or day > number_of_days:
1.197 - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-excluded"}))
1.198 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading event-day-excluded"}))
1.199 output.append(fmt.table_cell(on=0))
1.200
1.201 # Output normal days.
1.202
1.203 else:
1.204 - # Get event details.
1.205 - # NOTE: Can be made more efficient.
1.206 -
1.207 - date = (year, month, day)
1.208 - day_events = []
1.209 -
1.210 - for event_page, event_details in shown_events.get((year, month), []):
1.211 -
1.212 - # Test for the event on the current day.
1.213 -
1.214 - if event_details["start"] <= date <= event_details["end"]:
1.215 - day_events.append((event_page, event_details))
1.216 -
1.217 - # Output the day.
1.218 -
1.219 - if day_events:
1.220 - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-busy"}))
1.221 + if date in week_coverage:
1.222 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading event-day-busy"}))
1.223 else:
1.224 - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-empty"}))
1.225 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading event-day-empty"}))
1.226
1.227 output.append(fmt.div(on=1))
1.228 output.append(fmt.span(on=1, css_class="event-day-number"))
1.229 @@ -344,11 +410,47 @@
1.230 output.append(fmt.span(on=0))
1.231 output.append(fmt.div(on=0))
1.232
1.233 - output.append(fmt.div(on=1, css_class="event-summaries"))
1.234 + # End of day.
1.235 +
1.236 + output.append(fmt.table_cell(on=0))
1.237 +
1.238 + # End of day numbers.
1.239 +
1.240 + output.append(fmt.table_row(on=0))
1.241 +
1.242 + # Visit each set of scheduled events.
1.243 +
1.244 + for coverage, events in week_events:
1.245 +
1.246 + # Output each set.
1.247 +
1.248 + output.append(fmt.table_row(on=1))
1.249 +
1.250 + # Then, output day details.
1.251
1.252 - # Show event details.
1.253 + for weekday in range(0, 7):
1.254 + day = first_day + weekday
1.255 + date = (year, month, day)
1.256 +
1.257 + # Skip out-of-month days.
1.258 +
1.259 + if day < 1 or day > number_of_days:
1.260 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-excluded"}))
1.261 + output.append(fmt.table_cell(on=0))
1.262 + continue
1.263
1.264 - for event_page, event_details in day_events:
1.265 + # Output the day.
1.266 +
1.267 + if date in coverage:
1.268 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-busy"}))
1.269 + else:
1.270 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-empty"}))
1.271 +
1.272 + # Get event details for the current day.
1.273 +
1.274 + for event_page, event_details in events:
1.275 + if not (event_details["start"] <= date <= event_details["end"]):
1.276 + continue
1.277
1.278 # Get a pretty version of the page name.
1.279
1.280 @@ -363,24 +465,37 @@
1.281
1.282 if event_details["start"] == date:
1.283 css_classes.append("event-starts")
1.284 + start_of_event = 1
1.285 + else:
1.286 + start_of_event = 0
1.287
1.288 if event_details["end"] == date:
1.289 css_classes.append("event-ends")
1.290
1.291 # Output the event.
1.292
1.293 + if name_usage == "daily" or start_of_event or weekday == 0 or day == 1:
1.294 + hide_text = 0
1.295 + else:
1.296 + hide_text = 1
1.297 +
1.298 output.append(fmt.div(on=1, css_class=(" ".join(css_classes)),
1.299 style=("background-color: rgb(%d, %d, %d); color: rgb(%d, %d, %d);" % (bg + fg))))
1.300 - output.append(event_page.link_to_raw(request, wikiutil.escape(pretty_pagename)))
1.301 +
1.302 + if not hide_text:
1.303 + output.append(event_page.link_to_raw(request, wikiutil.escape(pretty_pagename)))
1.304 +
1.305 output.append(fmt.div(on=0))
1.306
1.307 - output.append(fmt.div(on=0))
1.308 -
1.309 # End of day.
1.310
1.311 output.append(fmt.table_cell(on=0))
1.312
1.313 - output.append(fmt.table_row(on=0))
1.314 + # End of set.
1.315 +
1.316 + output.append(fmt.table_row(on=0))
1.317 +
1.318 + # Process the next week...
1.319
1.320 first_day += 7
1.321