2.1 --- a/macros/EventAggregator.py Sun Mar 22 02:25:49 2009 +0100
2.2 +++ b/macros/EventAggregator.py Sun Mar 22 21:34:04 2009 +0100
2.3 @@ -13,6 +13,11 @@
2.4 import calendar
2.5 import re
2.6
2.7 +try:
2.8 + set
2.9 +except NameError:
2.10 + from sets import Set as set
2.11 +
2.12 __version__ = "0.1"
2.13
2.14 Dependencies = ['pages']
2.15 @@ -111,24 +116,40 @@
2.16 else:
2.17 return None
2.18
2.19 -def monthrange(first, last):
2.20 +def daterange(first, last):
2.21 results = []
2.22
2.23 + months_only = len(first) == 2
2.24 + start_year = first[0]
2.25 end_year = last[0]
2.26
2.27 - for year in range(first[0], end_year + 1):
2.28 - if year < last[0]:
2.29 + for year in range(start_year, end_year + 1):
2.30 + if year < end_year:
2.31 end_month = 12
2.32 else:
2.33 end_month = last[1]
2.34
2.35 - if year > first[0]:
2.36 + if year > start_year:
2.37 start_month = 1
2.38 else:
2.39 start_month = first[1]
2.40
2.41 for month in range(start_month, end_month + 1):
2.42 - results.append((year, month))
2.43 + if months_only:
2.44 + results.append((year, month))
2.45 + else:
2.46 + if month < end_month:
2.47 + _wd, end_day = calendar.monthrange(year, month)
2.48 + else:
2.49 + end_day = last[2]
2.50 +
2.51 + if month > start_month:
2.52 + start_day = 1
2.53 + else:
2.54 + start_day = first[2]
2.55 +
2.56 + for day in range(start_day, end_day + 1):
2.57 + results.append((year, month, day))
2.58
2.59 return results
2.60
2.61 @@ -153,9 +174,16 @@
2.62 """
2.63 Execute the 'macro' with the given 'args': an optional list of selected
2.64 category names (categories whose pages are to be shown), together with
2.65 - optional named arguments of the form "start=YYYY-MM" and "end=YYYY-MM"
2.66 - (indicating a restricted view of all events), and "mode=list" or
2.67 - "mode=calendar" (indicating the style of view).
2.68 + optional named arguments of the following forms:
2.69 +
2.70 + start=YYYY-MM shows event details starting from the specified month
2.71 + end=YYYY-MM shows event details ending at the specified month
2.72 +
2.73 + mode=calendar shows a calendar view of events
2.74 + mode=list shows a list of events by month
2.75 +
2.76 + names=daily shows the name of an event on every day of that event
2.77 + names=weekly shows the name of an event once per week
2.78 """
2.79
2.80 request = macro.request
2.81 @@ -178,6 +206,7 @@
2.82 calendar_start = None
2.83 calendar_end = None
2.84 mode = "calendar"
2.85 + name_usage = "daily"
2.86
2.87 for arg in parsed_args:
2.88 if arg.startswith("start="):
2.89 @@ -186,6 +215,8 @@
2.90 calendar_end = getMonth(arg[4:])
2.91 elif arg.startswith("mode="):
2.92 mode = arg[5:]
2.93 + elif arg.startswith("names="):
2.94 + name_usage = arg[6:]
2.95 else:
2.96 category_names.append(arg)
2.97
2.98 @@ -213,6 +244,9 @@
2.99
2.100 real_page_in_category = Page(request, pagename)
2.101 event_details = getEventDetails(real_page_in_category)
2.102 +
2.103 + # Define the event as the page together with its details.
2.104 +
2.105 event = (real_page_in_category, event_details)
2.106 events.append(event)
2.107
2.108 @@ -239,7 +273,7 @@
2.109 first = max(start_month, calendar_start or start_month)
2.110 last = min(end_month, calendar_end or end_month)
2.111
2.112 - for event_month in monthrange(first, last):
2.113 + for event_month in daterange(first, last):
2.114 if not shown_events.has_key(event_month):
2.115 shown_events[event_month] = []
2.116 shown_events[event_month].append(event)
2.117 @@ -256,7 +290,7 @@
2.118 first = calendar_start or earliest
2.119 last = calendar_end or latest
2.120
2.121 - for year, month in monthrange(first, last):
2.122 + for year, month in daterange(first, last):
2.123
2.124 # Either output a calendar view...
2.125
2.126 @@ -283,7 +317,7 @@
2.127 output.append(fmt.table_row(on=1))
2.128
2.129 for weekday in range(0, 7):
2.130 - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading"}))
2.131 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-weekday-heading"}))
2.132 output.append(fmt.text(_(weekday_labels[weekday])))
2.133 output.append(fmt.table_cell(on=0))
2.134
2.135 @@ -302,41 +336,73 @@
2.136
2.137 while first_day <= number_of_days:
2.138
2.139 - # Output a week.
2.140 + # Find events in this week and determine how to mark them on the
2.141 + # calendar.
2.142 +
2.143 + week_events = []
2.144 + week_coverage = set()
2.145 +
2.146 + week_start = (year, month, max(first_day, 1))
2.147 + week_end = (year, month, min(first_day + 6, number_of_days))
2.148 +
2.149 + # Get event details.
2.150 +
2.151 + for event in shown_events.get((year, month), []):
2.152 + event_page, event_details = event
2.153 +
2.154 + # Test for the event in the current week.
2.155 +
2.156 + if event_details["start"] <= week_end and event_details["end"] >= week_start:
2.157 +
2.158 + # Find the coverage of this week for the event.
2.159 +
2.160 + event_start = max(event_details["start"], week_start)
2.161 + event_end = min(event_details["end"], week_end)
2.162 + event_coverage = set(daterange(event_start, event_end))
2.163 +
2.164 + # Update the overall coverage.
2.165 +
2.166 + week_coverage.update(event_coverage)
2.167 +
2.168 + # Try and fit the event into the events list.
2.169 +
2.170 + for i, (coverage, events) in enumerate(week_events):
2.171 +
2.172 + # Where the event does not overlap with the current
2.173 + # element, add it alongside existing events.
2.174 +
2.175 + if not coverage.intersection(event_coverage):
2.176 + events.append(event)
2.177 + week_events[i] = coverage.union(event_coverage), events
2.178 + break
2.179 +
2.180 + # Make a new element in the list if the event cannot be
2.181 + # marked alongside existing events.
2.182 +
2.183 + else:
2.184 + week_events.append((event_coverage, [event]))
2.185 +
2.186 + # Output a week, starting with the day numbers.
2.187
2.188 output.append(fmt.table_row(on=1))
2.189
2.190 for weekday in range(0, 7):
2.191 day = first_day + weekday
2.192 + date = (year, month, day)
2.193
2.194 # Output out-of-month days.
2.195
2.196 if day < 1 or day > number_of_days:
2.197 - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-excluded"}))
2.198 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading event-day-excluded"}))
2.199 output.append(fmt.table_cell(on=0))
2.200
2.201 # Output normal days.
2.202
2.203 else:
2.204 - # Get event details.
2.205 - # NOTE: Can be made more efficient.
2.206 -
2.207 - date = (year, month, day)
2.208 - day_events = []
2.209 -
2.210 - for event_page, event_details in shown_events.get((year, month), []):
2.211 -
2.212 - # Test for the event on the current day.
2.213 -
2.214 - if event_details["start"] <= date <= event_details["end"]:
2.215 - day_events.append((event_page, event_details))
2.216 -
2.217 - # Output the day.
2.218 -
2.219 - if day_events:
2.220 - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-busy"}))
2.221 + if date in week_coverage:
2.222 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading event-day-busy"}))
2.223 else:
2.224 - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-empty"}))
2.225 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading event-day-empty"}))
2.226
2.227 output.append(fmt.div(on=1))
2.228 output.append(fmt.span(on=1, css_class="event-day-number"))
2.229 @@ -344,11 +410,47 @@
2.230 output.append(fmt.span(on=0))
2.231 output.append(fmt.div(on=0))
2.232
2.233 - output.append(fmt.div(on=1, css_class="event-summaries"))
2.234 + # End of day.
2.235 +
2.236 + output.append(fmt.table_cell(on=0))
2.237 +
2.238 + # End of day numbers.
2.239 +
2.240 + output.append(fmt.table_row(on=0))
2.241 +
2.242 + # Visit each set of scheduled events.
2.243 +
2.244 + for coverage, events in week_events:
2.245 +
2.246 + # Output each set.
2.247 +
2.248 + output.append(fmt.table_row(on=1))
2.249 +
2.250 + # Then, output day details.
2.251
2.252 - # Show event details.
2.253 + for weekday in range(0, 7):
2.254 + day = first_day + weekday
2.255 + date = (year, month, day)
2.256 +
2.257 + # Skip out-of-month days.
2.258 +
2.259 + if day < 1 or day > number_of_days:
2.260 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-excluded"}))
2.261 + output.append(fmt.table_cell(on=0))
2.262 + continue
2.263
2.264 - for event_page, event_details in day_events:
2.265 + # Output the day.
2.266 +
2.267 + if date in coverage:
2.268 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-busy"}))
2.269 + else:
2.270 + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-empty"}))
2.271 +
2.272 + # Get event details for the current day.
2.273 +
2.274 + for event_page, event_details in events:
2.275 + if not (event_details["start"] <= date <= event_details["end"]):
2.276 + continue
2.277
2.278 # Get a pretty version of the page name.
2.279
2.280 @@ -363,24 +465,37 @@
2.281
2.282 if event_details["start"] == date:
2.283 css_classes.append("event-starts")
2.284 + start_of_event = 1
2.285 + else:
2.286 + start_of_event = 0
2.287
2.288 if event_details["end"] == date:
2.289 css_classes.append("event-ends")
2.290
2.291 # Output the event.
2.292
2.293 + if name_usage == "daily" or start_of_event or weekday == 0 or day == 1:
2.294 + hide_text = 0
2.295 + else:
2.296 + hide_text = 1
2.297 +
2.298 output.append(fmt.div(on=1, css_class=(" ".join(css_classes)),
2.299 style=("background-color: rgb(%d, %d, %d); color: rgb(%d, %d, %d);" % (bg + fg))))
2.300 - output.append(event_page.link_to_raw(request, wikiutil.escape(pretty_pagename)))
2.301 +
2.302 + if not hide_text:
2.303 + output.append(event_page.link_to_raw(request, wikiutil.escape(pretty_pagename)))
2.304 +
2.305 output.append(fmt.div(on=0))
2.306
2.307 - output.append(fmt.div(on=0))
2.308 -
2.309 # End of day.
2.310
2.311 output.append(fmt.table_cell(on=0))
2.312
2.313 - output.append(fmt.table_row(on=0))
2.314 + # End of set.
2.315 +
2.316 + output.append(fmt.table_row(on=0))
2.317 +
2.318 + # Process the next week...
2.319
2.320 first_day += 7
2.321