# HG changeset patch # User Paul Boddie # Date 1422459784 -3600 # Node ID 06c78d7ef89d52a0120c47435be2e046d46edfe3 # Parent 84975914d568a364be695e4f2265ba6156549fd5 Added visualisation of other parties' free/busy details, handling periods without specific event information as provided by published or shared free/busy objects. diff -r 84975914d568 -r 06c78d7ef89d imip_manager.py --- a/imip_manager.py Wed Jan 28 14:29:24 2015 +0100 +++ b/imip_manager.py Wed Jan 28 16:43:04 2015 +0100 @@ -36,6 +36,7 @@ to_timezone from imiptools.mail import Messenger from imiptools.period import add_day_start_points, add_slots, convert_periods, \ + get_freebusy_details, \ get_scale, have_conflict, get_slots, get_spans, \ partition_by_day from imiptools.profile import Preferences @@ -441,6 +442,8 @@ requests = self._get_requests() + self.page.div(id="pending-requests") + if requests: self.page.p("Pending requests:") @@ -459,6 +462,55 @@ else: self.page.p("There are no pending requests.") + self.page.div.close() + + def show_participants_on_page(self): + + "Show participants for scheduling purposes." + + args = self.env.get_args() + participants = args.get("participants", []) + + try: + for name, value in args.items(): + if name.startswith("remove-participant-"): + i = int(name[len("remove-participant-"):]) + del participants[i] + break + except ValueError: + pass + + # Trim empty participants. + + while participants and not participants[-1].strip(): + participants.pop() + + # Show any specified participants together with controls to remove and + # add participants. + + self.page.div(id="participants") + + self.page.form(method="POST") + + self.page.p("Participants for scheduling:") + + for i, participant in enumerate(participants): + self.page.p() + self.page.input(name="participants", type="text", value=participant) + self.page.input(name="remove-participant-%d" % i, type="submit", value="Remove") + self.page.p.close() + + self.page.p() + self.page.input(name="participants", type="text") + self.page.input(name="add-participant", type="submit", value="Add") + self.page.p.close() + + self.page.form.close() + + self.page.div.close() + + return participants + # Full page output methods. def show_object(self, path_info): @@ -493,8 +545,8 @@ page = self.page self.show_requests_on_page() + participants = self.show_participants_on_page() - request_summary = self._get_request_summary() freebusy = self.store.get_freebusy(self.user) if not freebusy: @@ -516,17 +568,29 @@ # Details of users to invite to new events could be superimposed on the # calendar. - # Requests could be listed and linked to their tentative positions in - # the calendar. + # Requests are listed and linked to their tentative positions in the + # calendar. Other participants are also shown. + + request_summary = self._get_request_summary() + + period_groups = [request_summary, freebusy] + period_group_types = ["request", "freebusy"] + period_group_sources = ["Pending requests", "Your schedule"] + + for participant in participants: + period_groups.append(self.store.get_freebusy_for_other(self.user, get_uri(participant))) + period_group_types.append("freebusy") + period_group_sources.append(participant) groups = [] group_columns = [] - group_types = [] + group_types = period_group_types + group_sources = period_group_sources all_points = set() # Obtain time point information for each group of periods. - for periods, group_type in zip([request_summary, freebusy], ["request", "freebusy"]): + for periods in period_groups: periods = convert_periods(periods, tzid) # Get the time scale with start and end points. @@ -544,7 +608,6 @@ # Record the slots and all time points employed. groups.append(slots) - group_types.append(group_type) all_points.update([point for point, slot in slots]) # Partition the groups into days. @@ -552,8 +615,9 @@ days = {} partitioned_groups = [] partitioned_group_types = [] + partitioned_group_sources = [] - for slots, group_type in zip(groups, group_types): + for slots, group_type, group_source in zip(groups, group_types, group_sources): # Propagate time points to all groups of time slots. @@ -584,11 +648,26 @@ group_columns.append(columns) partitioned_groups.append(partitioned) partitioned_group_types.append(group_type) + partitioned_group_sources.append(group_source) page.table(border=1, cellspacing=0, cellpadding=5) + self.show_calendar_participant_headings(partitioned_group_sources, group_columns) self.show_calendar_days(days, partitioned_groups, partitioned_group_types, group_columns) page.table.close() + def show_calendar_participant_headings(self, partitioned_group_sources, group_columns): + page = self.page + + page.thead() + page.tr() + page.th("", class_="emptyheading") + + for source, columns in zip(partitioned_group_sources, group_columns): + page.th(source, class_="participantheading", colspan=columns) + + page.tr.close() + page.thead.close() + def show_calendar_days(self, days, partitioned_groups, partitioned_group_types, group_columns): page = self.page @@ -599,6 +678,8 @@ all_days = days.items() all_days.sort() + page.tbody() + # Produce a heading and time points for each day. for day, points in all_days: @@ -612,6 +693,8 @@ self.show_calendar_points(points, groups_for_day, partitioned_group_types, group_columns) + page.tbody.close() + def show_calendar_points(self, points, groups, group_types, group_columns): page = self.page @@ -645,9 +728,9 @@ # Show a column for each active period. for t in active: - if t: - start, end, uid = t[:3] - span = spans[uid] + if t and len(t) >= 2: + start, end, uid, key = get_freebusy_details(t) + span = spans[key] # Produce a table cell only at the start of the period # or when continued at the start of a day. @@ -657,7 +740,10 @@ page.td(class_="event", rowspan=span) obj = self._get_object(uid) - if obj: + + if not obj: + page.span("") + else: details = self._get_details(obj) summary = get_value(details, "SUMMARY") diff -r 84975914d568 -r 06c78d7ef89d imiptools/period.py --- a/imiptools/period.py Wed Jan 28 14:29:24 2015 +0100 +++ b/imiptools/period.py Wed Jan 28 16:43:04 2015 +0100 @@ -267,8 +267,9 @@ for point, active in slots: for t in active: - if t: - start, end, uid = t[:3] + if t and len(t) >= 2: + start, end, uid, key = get_freebusy_details(t) + try: start_slot = points.index(start) except ValueError: @@ -277,8 +278,27 @@ end_slot = points.index(end) except ValueError: end_slot = len(slots) - spans[uid] = end_slot - start_slot + spans[key] = end_slot - start_slot return spans +def get_freebusy_details(t): + + "Return a tuple of the form (start, end, uid, key) from 't'." + + # Handle both complete free/busy details... + + if len(t) > 2: + start, end, uid = t[:3] + key = uid + + # ...and published details without specific event details. + + else: + start, end = t[:2] + uid = None + key = (start, end) + + return start, end, uid, key + # vim: tabstop=4 expandtab shiftwidth=4