# HG changeset patch # User Paul Boddie # Date 1422630015 -3600 # Node ID 1d7cd23a754ec4214aad9051e232d9d93b30c430 # Parent 9e3d700236912f74745674dd82339611bfc2f84b Incorporated end points in slot details so that such information can be used in form controls for new event creation. diff -r 9e3d70023691 -r 1d7cd23a754e imip_manager.py --- a/imip_manager.py Fri Jan 30 13:30:57 2015 +0100 +++ b/imip_manager.py Fri Jan 30 16:00:15 2015 +0100 @@ -614,7 +614,7 @@ # Record the slots and all time points employed. groups.append(slots) - all_points.update([point for point, slot in slots]) + all_points.update([point for point, t in slots]) # Partition the groups into days. @@ -638,7 +638,11 @@ partitioned = {} for day, day_slots in partition_by_day(slots).items(): - columns = max(columns, max(map(lambda i: len(i[1]), day_slots))) + + intervals = [] + for point, (endpoint, active) in day_slots: + columns = max(columns, len(active)) + intervals.append((point, endpoint)) if not days.has_key(day): days[day] = set() @@ -646,9 +650,11 @@ # Convert each partition to a mapping from points to active # periods. - day_slots = dict(day_slots) - partitioned[day] = day_slots - days[day].update(day_slots.keys()) + partitioned[day] = dict(day_slots) + + # Record the divisions or intervals within each day. + + days[day].update(intervals) if group_type != "request" or columns: group_columns.append(columns) @@ -715,7 +721,7 @@ # Produce a heading and time points for each day. - for day, points in all_days: + for day, intervals in all_days: page.thead() page.tr() page.th(class_="dayheading", colspan=all_columns+1) @@ -727,13 +733,13 @@ groups_for_day = [partitioned.get(day) for partitioned in partitioned_groups] page.tbody() - self.show_calendar_points(points, groups_for_day, partitioned_group_types, group_columns) + self.show_calendar_points(intervals, groups_for_day, partitioned_group_types, group_columns) page.tbody.close() - def show_calendar_points(self, points, groups, group_types, group_columns): + def show_calendar_points(self, intervals, groups, group_types, group_columns): """ - Show the time 'points' along with period information from the given + Show the time 'intervals' along with period information from the given 'groups', having the indicated 'group_types', each with the number of columns given by 'group_columns'. """ @@ -742,32 +748,34 @@ # Produce a row for each time point. - points = list(points) - points.sort() + intervals = list(intervals) + intervals.sort() - for point in points: + for point, endpoint in intervals: continuation = point == get_start_of_day(point) page.tr() page.th(class_="timeslot") - self._time_point(point) + self._time_point(point, endpoint) page.th.close() # Obtain slots for the time point from each group. for columns, slots, group_type in zip(group_columns, groups, group_types): - active = slots and slots.get(point) + pt = slots and slots.get(point) # Where no periods exist for the given time interval, generate # an empty cell. Where a participant provides no periods at all, # the colspan is adjusted to be 1, not 0. - if not active: + if not pt or not pt[1]: page.td(class_="empty container", colspan=max(columns, 1)) - self._empty_slot(point) + self._empty_slot(point, endpoint) page.td.close() continue + endpoint, active = pt + slots = slots.items() slots.sort() spans = get_spans(slots) @@ -819,7 +827,7 @@ page.td.close() else: page.td(class_="empty container") - self._empty_slot(point) + self._empty_slot(point, endpoint) page.td.close() # Pad with empty columns. @@ -828,21 +836,26 @@ while i > 0: i -= 1 page.td(class_="empty container") - self._empty_slot(point) + self._empty_slot(point, endpoint) page.td.close() page.tr.close() - def _time_point(self, point): + def _time_point(self, point, endpoint): + page = self.page + value, identifier = self._slot_value_and_identifier(point, endpoint) + page.input(name="start", type="radio", value=value, id=identifier, class_="newevent") + page.label(self.format_time(point, "long"), class_="timepoint", for_=identifier) + + def _empty_slot(self, point, endpoint): page = self.page - pointstr = format_datetime(point) - page.input(name="start", type="radio", value=pointstr, id="start-%s" % pointstr, class_="newevent") - page.label(self.format_time(point, "long"), class_="timepoint", for_="start-%s" % pointstr) + value, identifier = self._slot_value_and_identifier(point, endpoint) + page.label("Make a new event in this period", class_="newevent popup", for_=identifier) - def _empty_slot(self, point): - page = self.page - pointstr = format_datetime(point) - page.label("Start a new event at this time", class_="newevent popup", for_="start-%s" % pointstr) + def _slot_value_and_identifier(self, point, endpoint): + value = "%s-%s" % tuple(map(format_datetime, [point, endpoint])) + identifier = "slot-%s" % value + return value, identifier def select_action(self): diff -r 9e3d70023691 -r 1d7cd23a754e imiptools/period.py --- a/imiptools/period.py Fri Jan 30 13:30:57 2015 +0100 +++ b/imiptools/period.py Fri Jan 30 16:00:15 2015 +0100 @@ -151,9 +151,10 @@ """ Return an ordered list of time slots from the given 'scale'. - Each slot is a tuple containing a point in time for the start of the slot, - together with a list of parallel event tuples, each tuple containing the - original details of an event. + Each slot is a tuple of the form (point, (endpoint, active)), where 'point' + indicates the start of the slot, 'endpoint' the end of the slot (or None), + and 'active' provides a list of parallel event tuples, with each tuple + containing the original details of an event. """ slots = [] @@ -162,6 +163,10 @@ points = scale.items() points.sort() + # Maintain a current slot so that the end can be added. + + current = None + for point, (starting, ending) in points: # Discard all active events ending at or before this start time. @@ -186,7 +191,14 @@ while active and active[-1] is None: active.pop() - slots.append((point, active[:])) + if current: + _point, _active = current + slots.append((_point, (point, _active))) + current = point, active[:] + + if current: + _point, _active = current + slots.append((_point, (None, _active))) return slots @@ -199,22 +211,22 @@ new_slots = [] current_date = None - previously_active = None + previously_active = [] - for point, active in slots: + for point, (endpoint, active) in slots: start_of_day = get_start_of_day(point) this_date = point.date() - # For each new day, add a slot for the start of the day where periods - # are active and where no such slot already exists. + # For each new day, add a slot for the start of the day where no such + # slot already exists. if this_date != current_date: current_date = this_date # Add any continuing periods. - if point != start_of_day and previously_active: - new_slots.append((start_of_day, previously_active)) + if point != start_of_day: + new_slots.append((start_of_day, (point, previously_active))) # Add the currently active periods at this point in time. @@ -231,31 +243,46 @@ those added. """ - new_slots = [] + for point in points: + i = bisect_left(slots, (point, ())) - for point in points: - i = bisect_left(slots, (point, None)) + # Ignore points of time for which slots already exist. + if i < len(slots) and slots[i][0] == point: continue - new_slots.append((point, i > 0 and slots[i-1][1] or [])) + # Update the endpoint of any preceding slot to refer to this new point. + + if i > 0: + _point, (_endpoint, previously_active) = slots[i-1] + slots[i-1] = _point, (point, previously_active) + else: + previously_active = [] - for t in new_slots: - insort_left(slots, t) + # Either insert a new slot before any following ones. + + if i < len(slots): + _point, (_endpoint, _active) = slots[i] + slots.insert(i, (point, (_point, previously_active))) + + # Or add a new slot at the end of the list. + + else: + slots.append((point, (None, previously_active))) def partition_by_day(slots): """ - Return a mapping from dates to time points provided by 'slots'. + Return a mapping from dates to entries provided by 'slots'. """ d = {} - for point, value in slots: + for point, (endpoint, value) in slots: day = point.date() if not d.has_key(day): d[day] = [] - d[day].append((point, value)) + d[day].append((point, (endpoint, value))) return d @@ -263,10 +290,10 @@ "Inspect the given 'slots', returning a mapping of event uids to spans." - points = [point for point, active in slots] + points = [point for point, (endpoint, active) in slots] spans = {} - for point, active in slots: + for point, (endpoint, active) in slots: for t in active: if t and len(t) >= 2: start, end, uid, key = get_freebusy_details(t)