- Revision
- 11422
- Author
- stearns
- Date
- 2006-08-15 13:04:20 -0700 (Tue, 15 Aug 2006)
Log Message
First step of several reminder changes: nothing user-visible yet, mostly reorganizing for what's to come: reminders are now attached to ContentItems instead of CalendarEvents, plus a little renaming.
Modified Paths
- trunk/chandler/application/Utility.py
- trunk/chandler/parcels/osaf/framework/blocks/ControlBlocks.py
- trunk/chandler/parcels/osaf/pim/__init__.py
- trunk/chandler/parcels/osaf/pim/calendar/Calendar.py
- trunk/chandler/parcels/osaf/pim/items.py
- trunk/chandler/parcels/osaf/views/detail/__init__.py
- trunk/chandler/parcels/osaf/views/detail/detail.py
- trunk/chandler/parcels/osaf/views/detail/detailblocks.py
- trunk/chandler/parcels/osaf/views/main/mainblocks.py
Added Paths
Removed Paths
Diff
Modified: trunk/chandler/application/Utility.py (11421 => 11422)
--- trunk/chandler/application/Utility.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/application/Utility.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -33,7 +33,7 @@ # with your name (and some helpful text). The comment's really there just to # cause Subversion to warn you of a conflict when you update, in case someone # else changes it at the same time you do (that's why it's on the same line). -SCHEMA_VERSION = "232" # stearns: Moved detail parcel to osaf/views +SCHEMA_VERSION = "233" # stearns: ContentItems own reminders now logger = None # initialized in initLogging()
Modified: trunk/chandler/parcels/osaf/framework/blocks/ControlBlocks.py (11421 => 11422)
--- trunk/chandler/parcels/osaf/framework/blocks/ControlBlocks.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/parcels/osaf/framework/blocks/ControlBlocks.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -1064,13 +1064,13 @@ return 0 return -1 - events = schema.ns('osaf.pim', view).eventsWithReminders - lastPastKey = events.findInIndex('reminderTime', 'last', matches) + itemsWithReminders = schema.ns('osaf.pim', view).itemsWithReminders + lastPastKey = itemsWithReminders.findInIndex('reminderTime', 'last', matches) if lastPastKey is not None: - return [(ev.reminderFireTime, ev ,ev.reminders.first()) - for ev in (view[key] for key in - events.iterindexkeys('reminderTime', None, lastPastKey))] + return [(item.reminderFireTime, item, item.reminders.first()) + for item in (view[key] for key in + itemsWithReminders.iterindexkeys('reminderTime', None, lastPastKey))] return [] @@ -1107,8 +1107,8 @@ if nextReminderTime is None: # The dialog didn't give us a time to fire; we'll fire at the # next non-pending reminder's time. - events = schema.ns('osaf.pim', self.itsView).eventsWithReminders - firstReminder = events.firstInIndex('reminderTime') + itemsWithReminders = schema.ns('osaf.pim', self.itsView).itemsWithReminders + firstReminder = itemsWithReminders.firstInIndex('reminderTime') if firstReminder is not None: nextReminderTime = firstReminder.reminderFireTime
Modified: trunk/chandler/parcels/osaf/pim/__init__.py (11421 => 11422)
--- trunk/chandler/parcels/osaf/pim/__init__.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/parcels/osaf/pim/__init__.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -16,8 +16,9 @@ # Import classes whose schemas are part of this parcel # (this should include all ContentItem subclasses in this package) # +from calculated import Calculated from items import ( - Calculated, ContentKind, ContentItem, ImportanceEnum, Group, Principal, + ContentKind, ContentItem, ImportanceEnum, Group, Principal, Project, Tag, TriageEnum, getTriageStatusName, getTriageStatusOrder, getNextTriageStatus, UserNotification ) @@ -30,7 +31,7 @@ from calendar.DateTimeUtil import (ampmNames, durationFormat, mediumDateFormat, monthNames, sampleDate, sampleTime, shortDateFormat, shortTimeFormat, weekdayNames, weekdayName) -from calendar.Reminders import Reminder, RemindableMixin +from reminders import Remindable, Reminder from tasks import Task, TaskMixin from mail import EmailAddress from application.Parcel import Reference @@ -121,6 +122,31 @@ filterAttributes=['isGenerated', 'modificationFor'] ) + itemKindCollection = KindCollection.update( + parcel, 'items', + kind = ContentItem.getKind(view), + recursive=True) + + itemsWithRemindersIncludingTrash = FilteredCollection.update( + parcel, 'itemsWithRemindersIncludingTrash', + source=itemKindCollection, + filterExpression="view.hasTrueValue(uuid, 'reminders')", + filterAttributes=['reminders']) + + itemsWithReminders = AppCollection.update( + parcel, 'itemsWithReminders', + source=itemsWithRemindersIncludingTrash, + exclusions=trashCollection, + trash=None, + ) + + # the monitor list assumes all reminders will be relativeTo + # effectiveStartTime, which is true in 0.6, but may not be in the future + itemsWithReminders.addIndex('reminderTime', 'compare', + compare='cmpReminderTime', + monitor=('startTime', 'allDay', 'anyTime' + 'reminders')) + # the "All" / "My" collection allCollection = SmartCollection.update(parcel, 'allCollection', displayName=_(u"Dashboard"), @@ -146,19 +172,6 @@ events.addIndex('icalUID', 'value', attribute='icalUID') - eventsWithRemindersIncludingTrash = FilteredCollection.update( - parcel, 'eventsWithRemindersIncludingTrash', - source=events, - filterExpression="view.hasTrueValue(uuid, 'reminders')", - filterAttributes=['reminders']) - - eventsWithReminders = AppCollection.update( - parcel, 'eventsWithReminders', - source=eventsWithRemindersIncludingTrash, - exclusions=trashCollection, - trash=None, - ) - longEvents = FilteredCollection.update(parcel, 'longEvents', source = events, filterMethod= (LongEventFilter(None, parcel), 'isLongEvent'), @@ -176,13 +189,6 @@ superindex=(events, events.__collection__, 'effectiveEndNoTZ')) - # the monitor list assumes all reminders will be relativeTo - # effectiveStartTime, which is true in 0.6, but may not be in the future - eventsWithReminders.addIndex('reminderTime', 'compare', - compare='cmpReminderTime', - monitor=('startTime', 'allDay', 'anyTime' - 'reminders')) - masterFilter = "view.hasTrueValues(uuid, 'occurrences', 'rruleset')" masterEvents = FilteredCollection.update(parcel, 'masterEvents', source = events,
Added: trunk/chandler/parcels/osaf/pim/calculated.py (11421 => 11422)
--- trunk/chandler/parcels/osaf/pim/calculated.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/parcels/osaf/pim/calculated.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -0,0 +1,36 @@ +# Copyright (c) 2003-2006 Open Source Applications Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +__parcel__ = "osaf.pim" + +#import logging +#logger = logging.getLogger(__name__) + +class Calculated(property): + """ + A property with type information, in the style of our schema.* objects. + - This could become a schema class when it grows up :-) + - I'm open to a different name: I think it oughta be schema.Property, but pje + thought Calculated was better... + """ + def __new__(cls, schema_type, basedOn, fget, fset=None, fdel=None, + doc=None): + return property.__new__(cls, fget, fset, fdel, doc) + + def __init__(self, schema_type, basedOn, fget, fset=None, fdel=None, + doc=None): + property.__init__(self, fget, fset, fdel, doc) + self.type = schema_type + self.basedOn = basedOn Property changes on: trunk/chandler/parcels/osaf/pim/calculated.py ___________________________________________________________________ Name: svn:executable + * Name: svn:mime-type + text/plain Name: svn:eol-style + native
Modified: trunk/chandler/parcels/osaf/pim/calendar/Calendar.py (11421 => 11422)
--- trunk/chandler/parcels/osaf/pim/calendar/Calendar.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/parcels/osaf/pim/calendar/Calendar.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -25,16 +25,17 @@ from application import schema from osaf.pim.contacts import Contact -from osaf.pim.items import Calculated, ContentItem +from osaf.pim.calculated import Calculated +from osaf.pim.items import ContentItem from osaf.pim.notes import Note from osaf.pim.calendar import Recurrence from application.dialogs import RecurrenceDialog import wx from TimeZone import formatTime -from Reminders import RemindableMixin, Reminder from osaf.pim.calendar.TimeZone import coerceTimeZone, TimeZoneInfo from osaf.pim.calendar import DateTimeUtil +from osaf.pim.reminders import Remindable, Reminder from PyICU import DateFormat, DateFormatSymbols, ICUtzinfo from datetime import datetime, time, timedelta import itertools @@ -269,7 +270,7 @@ -class CalendarEventMixin(RemindableMixin): +class CalendarEventMixin(ContentItem): """ This is the set of CalendarEvent-specific attributes. This Kind is 'mixed in' to others kinds to create Kinds that can be instantiated.
Deleted: trunk/chandler/parcels/osaf/pim/calendar/Reminders.py (11421 => 11422)
--- trunk/chandler/parcels/osaf/pim/calendar/Reminders.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/parcels/osaf/pim/calendar/Reminders.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -1,209 +0,0 @@ -# Copyright (c) 2003-2006 Open Source Applications Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -from application import schema -from osaf.pim.items import Calculated, ContentItem -from datetime import datetime, time, timedelta -from PyICU import ICUtzinfo - - -class Reminder(schema.Item): - delta = schema.One( - schema.TimeDelta, - doc="The amount in advance this reminder should occur (usually negative!)", - ) - - relativeTo = schema.One( - schema.Text, - initialValue='effectiveStartTime', - ) - - reminderItems = schema.Sequence( - "RemindableMixin", - inverse="reminders", - initialValue=[] - ) - - expiredReminderItems = schema.Sequence( - "RemindableMixin", - inverse="expiredReminders", - initialValue=[] - ) - - snoozedUntil = schema.One( - schema.DateTimeTZ, - defaultValue=None - ) - - schema.addClouds( - sharing = schema.Cloud(delta, relativeTo, snoozedUntil) - ) - - def getBaseTimeFor(self, remindable): - """ - Get the relative-to time for this remindable's next reminder - so that the UI can generate a message relative to it. - """ - return getattr(remindable, self.relativeTo, datetime.max) - - def getNextReminderTimeFor(self, remindable): - """ Get the time for this remindable's next reminder """ - result = self.snoozedUntil or \ - (self.getBaseTimeFor(remindable) + self.delta) - if result.tzinfo is None: - result = result.replace(tzinfo=ICUtzinfo.default) - return result - -class RemindableMixin(ContentItem): - reminders = schema.Sequence( - Reminder, - inverse=Reminder.reminderItems, - initialValue=[] - ) - - expiredReminders = schema.Sequence( - Reminder, - inverse=Reminder.expiredReminderItems, - initialValue=[] - ) - - schema.addClouds( - copying = schema.Cloud(reminders,expiredReminders), - sharing = schema.Cloud( - byCloud = [reminders, expiredReminders] - ) - ) - - def getReminderInterval(self): - for attr in ("reminders", "expiredReminders"): - if (self.hasLocalAttributeValue(attr)): - #@@@ This assumes we've only got 0 or 1 reminders. - first = getattr(self, attr).first() - try: - return first.delta - except AttributeError: - pass - - return None - - def setReminderInterval(self, delta): - reminderCollection = self.reminders - firstReminder = reminderCollection.first() - - if firstReminder is None: - reminderCollection = self.expiredReminders - firstReminder = reminderCollection.first() - - if firstReminder is not None: - reminderCollection.remove(firstReminder) - if not (len(firstReminder.reminderItems) or \ - len(firstReminder.expiredReminderItems)): - firstReminder.delete() - - if delta is not None: - self.makeReminder(delta, checkExpired=True) - - reminderInterval = Calculated( - schema.TimeDelta, - basedOn=('reminders',), - fget=getReminderInterval, - fset=setReminderInterval, - doc="Reminder interval, computed from the first unexpired reminder." - ) - - def getReminderFireTime(self): - """ - A simplification of the possible complexity of reminder, assumes one - or zero reminders. Returns a datetime or None. - """ - reminder = self.reminders.first() - if reminder is None: - return None - else: - return reminder.getNextReminderTimeFor(self) - - reminderFireTime = Calculated( - schema.DateTimeTZ, - basedOn=('startTime', 'allDay', 'anyTime', 'reminders'), - fget=getReminderFireTime, - doc="Reminder fire time, or None for no unexpired reminders") - - def makeReminder(self, delta, checkExpired=False): - # @@@ I think the proxy code should override calls to this method - # add a separate reference to this reminder to each generated event, - # (or something like that). (Remindable.snoozeReminder will call this - # method; that operation should only affect the actual event, not the - # series) - newReminder = Reminder(None, delta=delta, itsView=self.itsView) - - addThisTo = self.reminders - - if checkExpired: - nextTime = newReminder.getNextReminderTimeFor(self) - - if (nextTime is not None and - nextTime < datetime.now(ICUtzinfo.default)): - addThisTo = self.expiredReminders - - addThisTo.add(newReminder) - return newReminder - - def dismissReminder(self, reminder): - """ Dismiss this reminder. """ - - # Make sure the next one's around, so we'll prime the reminder- - # watching mechanism to alert us about it. We also check that - # reminders for past events don't trigger this one. - now = datetime.now(ICUtzinfo.default) - - try: - getNextOccurrenceMethod = self.getNextOccurrence - except AttributeError: - pass - else: - # Get the next occurrence of this event. We - # don't need to do anything with it; we just - # want to make sure it's been instantiated - # so that the next reminder will fire. - getNextOccurrenceMethod(after=now) - - # In the case of generated occurrences, the reminder - # may already have fired (cf fixReminders() in - # CalendarEventMixin.getNextOccurrence - if reminder in self.reminders: - self.reminders.remove(reminder) - if getattr(reminder, 'snoozedUntil', None) is not None: - # This is a "snooze" reminder, just toss it. - assert len(reminder.reminderItems) == 0 - assert len(reminder.expiredReminderItems) == 0 - reminder.delete() - else: - if not reminder in self.expiredReminders: - self.expiredReminders.add(reminder) - - - - def snoozeReminder(self, reminder, delay): - """ Snooze this reminder for this long. """ - # Dismiss the original reminder - originalTime = reminder.getNextReminderTimeFor(self) - self.dismissReminder(reminder) - - # Make a new reminder for this event - newReminder = Reminder(None, itsView=self.itsView, - snoozedUntil=(datetime.now(ICUtzinfo.default) + - delay)) - self.reminders.add(newReminder) - return newReminder
Modified: trunk/chandler/parcels/osaf/pim/items.py (11421 => 11422)
--- trunk/chandler/parcels/osaf/pim/items.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/parcels/osaf/pim/items.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -31,6 +31,7 @@ from i18n import ChandlerMessageFactory as _ from osaf import messages from PyICU import ICUtzinfo +from reminders import Remindable logger = logging.getLogger(__name__) @@ -67,26 +68,8 @@ def getNextTriageStatus(value): return TriageEnum.values[(triageStatusOrder[value]+1) % len(TriageEnum.values)] -class Calculated(property): +class ContentItem(Remindable): """ - A property with type information, in the style of our schema.* objects. - - This could become a schema class when it grows up :-) - - I'm open to a different name: I think it oughta be schema.Property, but pje - thought Calculated was better... - """ - def __new__(cls, schema_type, basedOn, fget, fset=None, fdel=None, - doc=None): - return property.__new__(cls, fget, fset, fdel, doc) - - def __init__(self, schema_type, basedOn, fget, fset=None, fdel=None, - doc=None): - property.__init__(self, fget, fset, fdel, doc) - self.type = schema_type - self.basedOn = basedOn - - -class ContentItem(schema.Item): - """ Content Item Content Item is the abstract super-kind for things like Contacts, Calendar
Added: trunk/chandler/parcels/osaf/pim/reminders.py (11421 => 11422)
--- trunk/chandler/parcels/osaf/pim/reminders.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/parcels/osaf/pim/reminders.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -0,0 +1,209 @@ +# Copyright (c) 2003-2006 Open Source Applications Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from application import schema +from calculated import Calculated +from datetime import datetime, time, timedelta +from PyICU import ICUtzinfo + + +class Reminder(schema.Item): + delta = schema.One( + schema.TimeDelta, + doc="The amount in advance this reminder should occur (usually negative!)", + ) + + relativeTo = schema.One( + schema.Text, + initialValue='effectiveStartTime', + ) + + reminderItems = schema.Sequence( + "Remindable", + inverse="reminders", + initialValue=[] + ) + + expiredReminderItems = schema.Sequence( + "Remindable", + inverse="expiredReminders", + initialValue=[] + ) + + snoozedUntil = schema.One( + schema.DateTimeTZ, + defaultValue=None + ) + + schema.addClouds( + sharing = schema.Cloud(delta, relativeTo, snoozedUntil) + ) + + def getBaseTimeFor(self, remindable): + """ + Get the relative-to time for this remindable's next reminder + so that the UI can generate a message relative to it. + """ + return getattr(remindable, self.relativeTo, datetime.max) + + def getNextReminderTimeFor(self, remindable): + """ Get the time for this remindable's next reminder """ + result = self.snoozedUntil or \ + (self.getBaseTimeFor(remindable) + self.delta) + if result.tzinfo is None: + result = result.replace(tzinfo=ICUtzinfo.default) + return result + +class Remindable(schema.Item): + reminders = schema.Sequence( + Reminder, + inverse=Reminder.reminderItems, + initialValue=[] + ) + + expiredReminders = schema.Sequence( + Reminder, + inverse=Reminder.expiredReminderItems, + initialValue=[] + ) + + schema.addClouds( + copying = schema.Cloud(reminders,expiredReminders), + sharing = schema.Cloud( + byCloud = [reminders, expiredReminders] + ) + ) + + def getReminderInterval(self): + for attr in ("reminders", "expiredReminders"): + if (self.hasLocalAttributeValue(attr)): + #@@@ This assumes we've only got 0 or 1 reminders. + first = getattr(self, attr).first() + try: + return first.delta + except AttributeError: + pass + + return None + + def setReminderInterval(self, delta): + reminderCollection = self.reminders + firstReminder = reminderCollection.first() + + if firstReminder is None: + reminderCollection = self.expiredReminders + firstReminder = reminderCollection.first() + + if firstReminder is not None: + reminderCollection.remove(firstReminder) + if not (len(firstReminder.reminderItems) or \ + len(firstReminder.expiredReminderItems)): + firstReminder.delete() + + if delta is not None: + self.makeReminder(delta, checkExpired=True) + + reminderInterval = Calculated( + schema.TimeDelta, + basedOn=('reminders',), + fget=getReminderInterval, + fset=setReminderInterval, + doc="Reminder interval, computed from the first unexpired reminder." + ) + + def getReminderFireTime(self): + """ + A simplification of the possible complexity of reminder, assumes one + or zero reminders. Returns a datetime or None. + """ + reminder = self.reminders.first() + if reminder is None: + return None + else: + return reminder.getNextReminderTimeFor(self) + + reminderFireTime = Calculated( + schema.DateTimeTZ, + basedOn=('startTime', 'allDay', 'anyTime', 'reminders'), + fget=getReminderFireTime, + doc="Reminder fire time, or None for no unexpired reminders") + + def makeReminder(self, delta, checkExpired=False): + # @@@ I think the proxy code should override calls to this method + # add a separate reference to this reminder to each generated event, + # (or something like that). (Remindable.snoozeReminder will call this + # method; that operation should only affect the actual event, not the + # series) + newReminder = Reminder(None, delta=delta, itsView=self.itsView) + + addThisTo = self.reminders + + if checkExpired: + nextTime = newReminder.getNextReminderTimeFor(self) + + if (nextTime is not None and + nextTime < datetime.now(ICUtzinfo.default)): + addThisTo = self.expiredReminders + + addThisTo.add(newReminder) + return newReminder + + def dismissReminder(self, reminder): + """ Dismiss this reminder. """ + + # Make sure the next one's around, so we'll prime the reminder- + # watching mechanism to alert us about it. We also check that + # reminders for past events don't trigger this one. + now = datetime.now(ICUtzinfo.default) + + try: + getNextOccurrenceMethod = self.getNextOccurrence + except AttributeError: + pass + else: + # Get the next occurrence of this event. We + # don't need to do anything with it; we just + # want to make sure it's been instantiated + # so that the next reminder will fire. + getNextOccurrenceMethod(after=now) + + # In the case of generated occurrences, the reminder + # may already have fired (cf fixReminders() in + # CalendarEventMixin.getNextOccurrence + if reminder in self.reminders: + self.reminders.remove(reminder) + if getattr(reminder, 'snoozedUntil', None) is not None: + # This is a "snooze" reminder, just toss it. + assert len(reminder.reminderItems) == 0 + assert len(reminder.expiredReminderItems) == 0 + reminder.delete() + else: + if not reminder in self.expiredReminders: + self.expiredReminders.add(reminder) + + + + def snoozeReminder(self, reminder, delay): + """ Snooze this reminder for this long. """ + # Dismiss the original reminder + originalTime = reminder.getNextReminderTimeFor(self) + self.dismissReminder(reminder) + + # Make a new reminder for this event + newReminder = Reminder(None, itsView=self.itsView, + snoozedUntil=(datetime.now(ICUtzinfo.default) + + delay)) + self.reminders.add(newReminder) + return newReminder Property changes on: trunk/chandler/parcels/osaf/pim/reminders.py ___________________________________________________________________ Name: svn:executable + * Name: svn:mime-type + text/plain Name: svn:eol-style + native
Modified: trunk/chandler/parcels/osaf/views/detail/__init__.py (11421 => 11422)
--- trunk/chandler/parcels/osaf/views/detail/__init__.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/parcels/osaf/views/detail/__init__.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -30,7 +30,6 @@ CalendarRecurrenceEndAreaBlock, CalendarRecurrencePopupAreaBlock, CalendarRecurrenceSpacer2Area, - CalendarReminderAreaBlock, CalendarStampBlock, CalendarTimeAEBlock, CalendarTimeZoneAreaBlock, @@ -45,6 +44,7 @@ MailMessageButtonBlock, OutboundOnlyAreaBlock, PrivateSwitchButtonBlock, + ReminderAreaBlock, StaticRedirectAttribute, StaticRedirectAttributeLabel, StaticTextLabel,
Modified: trunk/chandler/parcels/osaf/views/detail/detail.py (11421 => 11422)
--- trunk/chandler/parcels/osaf/views/detail/detail.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/parcels/osaf/views/detail/detail.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -684,22 +684,79 @@ class ReminderConditionalBlock(Item): def shouldShow (self, item): - return item.isAttributeModifiable('reminders') \ - or len(item.reminders) > 0 + return isinstance(item, pim.CalendarEventMixin) and \ + (item.isAttributeModifiable('reminders') \ + or len(item.reminders) > 0) def getWatchList(self): watchList = super(ReminderConditionalBlock, self).getWatchList() watchList.append((self.item, 'reminders')) return watchList -class CalendarReminderSpacerBlock(ReminderConditionalBlock, - SynchronizedSpacerBlock): +class ReminderSpacerBlock(ReminderConditionalBlock, + SynchronizedSpacerBlock): pass -class CalendarReminderAreaBlock (ReminderConditionalBlock, - DetailSynchronizedContentItemDetail): +class ReminderAreaBlock(ReminderConditionalBlock, + DetailSynchronizedContentItemDetail): pass +class ReminderAttributeEditor(ChoiceAttributeEditor): + def GetControlValue (self, control): + """ + Get the reminder delta value for the current selection. + """ + # @@@ i18n For now, assumes that the menu will be a number of minutes, + # followed by a space (eg, "1 minute", "15 minutes", etc), or something + # that doesn't match this (eg, "None") for no-alarm. + menuChoice = control.GetStringSelection() + try: + minuteCount = int(menuChoice.split(u" ")[0]) + except ValueError: + # "None" + value = None + else: + value = timedelta(minutes=-minuteCount) + return value + + def SetControlValue (self, control, value): + """ + Select the choice that matches this delta value. + """ + # We also take this opportunity to populate the menu + existingValue = self.GetControlValue(control) + if existingValue != value or control.GetCount() == 0: + # rebuild the list of choices + choices = self.GetChoices() + control.Clear() + control.AppendItems(choices) + + if value is None: + choiceIndex = 0 # the "None" choice + else: + minutes = ((value.days * 1440) + (value.seconds / 60)) + reminderChoice = (minutes == -1) and _(u"1 minute") or (_(u"%(numberOf)i minutes") % {'numberOf': -minutes}) + choiceIndex = control.FindString(reminderChoice) + # If we can't find the choice, just show "None" - this'll happen if this event's reminder has been "snoozed" + if choiceIndex == -1: + choiceIndex = 0 # the "None" choice + control.Select(choiceIndex) + + def GetAttributeValue (self, item, attributeName): + """ + Get the value from the specified attribute of the item. + """ + return item.reminderInterval + + def SetAttributeValue (self, item, attributeName, value): + """Set the value of the attribute given by the value. + """ + if not self.ReadOnly((item, attributeName)) and \ + value != self.GetAttributeValue(item, attributeName): + + setattr(item, attributeName, value) + self.AttributeChanged() + class TransparencyConditionalBlock(Item): def shouldShow (self, item): # don't show for anyTime or @time events (but do show for allDay @@ -1035,62 +1092,6 @@ self.SetControlValue(self.control, self.GetAttributeValue(item, attributeName)) -class ReminderAttributeEditor(ChoiceAttributeEditor): - def GetControlValue (self, control): - """ - Get the reminder delta value for the current selection. - """ - # @@@ i18n For now, assumes that the menu will be a number of minutes, - # followed by a space (eg, "1 minute", "15 minutes", etc), or something - # that doesn't match this (eg, "None") for no-alarm. - menuChoice = control.GetStringSelection() - try: - minuteCount = int(menuChoice.split(u" ")[0]) - except ValueError: - # "None" - value = None - else: - value = timedelta(minutes=-minuteCount) - return value - - def SetControlValue (self, control, value): - """ - Select the choice that matches this delta value. - """ - # We also take this opportunity to populate the menu - existingValue = self.GetControlValue(control) - if existingValue != value or control.GetCount() == 0: - # rebuild the list of choices - choices = self.GetChoices() - control.Clear() - control.AppendItems(choices) - - if value is None: - choiceIndex = 0 # the "None" choice - else: - minutes = ((value.days * 1440) + (value.seconds / 60)) - reminderChoice = (minutes == -1) and _(u"1 minute") or (_(u"%(numberOf)i minutes") % {'numberOf': -minutes}) - choiceIndex = control.FindString(reminderChoice) - # If we can't find the choice, just show "None" - this'll happen if this event's reminder has been "snoozed" - if choiceIndex == -1: - choiceIndex = 0 # the "None" choice - control.Select(choiceIndex) - - def GetAttributeValue (self, item, attributeName): - """ - Get the value from the specified attribute of the item. - """ - return item.reminderInterval - - def SetAttributeValue (self, item, attributeName, value): - """Set the value of the attribute given by the value. - """ - if not self.ReadOnly((item, attributeName)) and \ - value != self.GetAttributeValue(item, attributeName): - - setattr(item, attributeName, value) - self.AttributeChanged() - class RecurrenceAttributeEditor(ChoiceAttributeEditor): # These are the values we pass around; they're the same as the menu indices. # This is a list of the frequency enumeration names (defined in
Modified: trunk/chandler/parcels/osaf/views/detail/detailblocks.py (11421 => 11422)
--- trunk/chandler/parcels/osaf/views/detail/detailblocks.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/parcels/osaf/views/detail/detailblocks.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -398,6 +398,27 @@ position=0.5, border=RectType(0,6,0,6)).install(parcel) + reminderArea = \ + makeArea(parcel, 'ReminderArea', + baseClass=ReminderAreaBlock, + childrenBlocks=[ + makeLabel(parcel, _(u'alarm'), borderTop=5), + makeSpacer(parcel, width=8), + makeEditor(parcel, 'EditReminder', + viewAttribute=u'reminderInterval', + presentationStyle={ + # @@@ XXX i18n: the code assumes that if the value + # starts with a digit, it's a number of minutes; if not, + # it's None. + 'choices': [_(u'None'), _(u'1 minute'), _(u'5 minutes'), + _(u'10 minutes'), _(u'30 minutes'), + _(u'60 minutes'), _(u'90 minutes')], + 'format' : 'reminder' + }, + stretchFactor=0.0, + minimumSize=SizeType(100, -1))], + position=0.81).install(parcel) + # The Note AEBlock notesBlock = makeEditor(parcel, 'NotesBlock', viewAttribute=u'body', @@ -425,6 +446,9 @@ makeSpacer(parcel, height=6, position=0.01).install(parcel), parcel['MarkupBar'], headlineArea, + makeSpacer(parcel, height=7, baseClass=ReminderSpacerBlock, + position=0.809999).install(parcel), + reminderArea, makeSpacer(parcel, height=7, position=0.8999).install(parcel), notesBlock, appearsInArea, @@ -578,26 +602,6 @@ presentationStyle={'format': 'ends'}, stretchFactor=0.0, size=SizeType(75, -1))]) - - reminderArea = \ - makeArea(parcel, 'CalendarReminderArea', - baseClass=CalendarReminderAreaBlock, - childrenBlocks=[ - makeLabel(parcel, _(u'alarm'), borderTop=5), - makeSpacer(parcel, width=8), - makeEditor(parcel, 'EditReminder', - viewAttribute=u'reminderInterval', - presentationStyle={ - # @@@ XXX i18n: the code assumes that if the value - # starts with a digit, it's a number of minutes; if not, - # it's None. - 'choices': [_(u'None'), _(u'1 minute'), _(u'5 minutes'), - _(u'10 minutes'), _(u'30 minutes'), - _(u'60 minutes'), _(u'90 minutes')], - 'format' : 'reminder' - }, - stretchFactor=0.0, - minimumSize=SizeType(100, -1))]) timeDescriptionArea = \ makeArea(parcel, 'CalendarTimeDescriptionArea', @@ -641,10 +645,7 @@ locationArea, makeSpacer(parcel, height=4), #timeDescriptionArea, - timeEditArea, - makeSpacer(parcel, height=7, - baseClass=CalendarReminderSpacerBlock), - reminderArea]).install(parcel) + timeEditArea]).install(parcel) makeSubtree(parcel, osaf.pim.CalendarEventMixin, [ calendarDetails ])
Modified: trunk/chandler/parcels/osaf/views/main/mainblocks.py (11421 => 11422)
--- trunk/chandler/parcels/osaf/views/main/mainblocks.py 2006-08-15 19:56:04 UTC (rev 11421) +++ trunk/chandler/parcels/osaf/views/main/mainblocks.py 2006-08-15 20:04:20 UTC (rev 11422) @@ -39,7 +39,7 @@ ReminderTimer.update( parcel, 'ReminderTimer', event = main.ReminderTime, - contents = pim_ns.eventsWithReminders) + contents = pim_ns.itemsWithReminders) SidebarBranchPointDelegateInstance = SidebarBranchPointDelegate.update( parcel, 'SidebarBranchPointDelegateInstance',
_______________________________________________ Commits mailing list [email protected] http://lists.osafoundation.org/mailman/listinfo/commits
