Nice job Grant!
See comments in-line
-Brian
On Dec 20, 2006, at 7:17 AM, Grant Baillie wrote:
Howdy, chandler-dev@:
So, I'm getting ready to commit the first round of changes for edit/
update in the next day or two. This should cover the domain model
changes for supporting "lastModified", and I’ve hooked up enough of
the UI (e.g., by adding a field or two to the detail view) that you
can tell edit state is being tracked.
Here's a high-level overview. It's perhaps a little long and heavy
on using the code as illustration, but comments or suggestions are
welcome. If you're a managerial type, there are some TODOs at the
end, too.
1. In osaf.pim.items, there's now a Modification enumerated type
that is used to say what the last change to a given ContentItem was:
class Modification(schema.Enumeration):
"""
Enumeration of the types of modification that are part of
the edit/update workflows (a.k.a. "Stamping Storyboards")
"""
values = { "edited":100, "queued":200, "sent":300, "updated":400 }
2. The design requires some state to be associated with each item;
for example, once an invitation has been sent, future sendings are
actually called "updates". So, besides just storing the what the
last modification, there's a set of flags that is used to maintain
that history:
(added to ContentItem):
lastModification = schema.One(
Modification,
doc="What the last modification was"
)
modifiedFlags = schema.Many(
Modification,
initialValue=set([]),
description='Used to track the modification state of the item'
)
3. I added the following method to ContentItem:
def changeEditState(self, modType=Modification.edited, who=None,
when=None):
This does the job of updating the lastModified-related attributes,
including modifiedFlags, as appropriate. (See #7 for how the UI
ends up calling this).
4. There's a "byline" Calculated attribute on ContentItem; this is
used to show a string like "Edited by me on 12/21/2006" in the
detail view.
5. I added an "error" attribute (a schema.Text) that stores a
string containing the last error associated with a given item. At
the moment, it’s only used during mail delivery failures, but in
theory it could be used for sharing problems, too.
6. I changed the mail delivery code to use
ContentItem.changeEditState(); in particular, we set the edited
state to queued when we first hand off your message to the twisted
thread for delivery, and set the sent/updated/error attributes as
appropriate when done.
7. Making sure the UI calls changeEditState() when the user makes
changes was an interesting strategy. One option I tried, but seemed
a little haphazard, was to find all the setattr() calls in the
various AttributeEditor subclasses, and add calls to changeEditState
(). I realized this would also lead to weirdness if, for example,
you edited a recurring event, because there the proxy would delay
the actual attribute change till the user had confirmed it, but the
change to lastModified would have happened anyway.
So, for now I went via a different route, which was to retrofit the
occurrence proxy to call changeEditState(), even for items that
aren’t recurring events. There are probably a few cases where we
are explicitly not using the proxy in the UI; it's on my list to
seek out and find those, and deal with the case where we want to
call changeEditState() but not have the recurring event dialog show
up.
8. I reworked some of Bryan Stearns' code for the communication
column icons a little. I left the code that figures out what icon
to use in the osaf.views.main.summaryblocks, but I moved the
calculation of the various bits that contribute to an item's
"communication state" over to an Annotation in osaf.pim.mail:
class CommunicationStatus(schema.Annotation):
schema.kindInfo(annotates=items.ContentItem)
# These flag bits govern the sort position of each
communications state:
# UPDATE = 1
# IN = 1
# OUT = 1
# DRAFT = 1
# QUEUED = 1
# SENT = 1
# NEEDS_REPLY = 1
# READ = 1
# ERROR = 1
UPDATE, IN, OUT, DRAFT, QUEUED, SENT, NEEDS_REPLY, READ, ERROR = (
1<<n for n in xrange(9)
)
@staticmethod
def getItemCommState(itemOrUUID, view=None):
"""Given an item or a UUID, determine its communications
status"""
...
attributes = ... # attributes that contribute toward
Communication status
status = schema.Calculated(
schema.Integer,
basedOn=tuple(t[0] for t in attributes),
fget=lambda self: self.getItemCommState(self.itsItem),
doc="A 'bitfield' of (UPDATE, IN, OUT, DRAFT, ...) |'ed
together"
9. The index used by the communication column now uses the above
CommunicationStatus.status attribute (and knows the dependency on
CommunicationStatus.attributes). Howvever, as Bryan originally
designed it, this could be done via a method index and the
getItemCommState method.
10. In the detail view, I added fields to show the byline and error
string (if any), and changed the "from" field to be a "send as" for
outgoing messages. As I'm a domain-model troglodyte lacking in high-
level UI sensibilities, these probably need some tweaking w.r.t
positioning, fonts and all that fun stuff.
TODO:
=====
- Add support for lastModifiedBy. (Currently, this value is always
None, which means it's treated as being by the user). Mainly, I/we
need to decide on using Contact vs EmailAddress here.
- Review the various CommunicationStatus states, to make sure they
match the design spec.
- Look into how all this works (or doesn't!) with recurring events.
- Currently, there's an SMTPDeliveryStatus class in the mail code
that tracks DRAFT/QUEUED/SENT/ERROR state. Look into unifying this
with the enumerated type above, or for moving the communication-
related Modification values into the mail module somehow. If I knew
how to do this cleanly, I probably would have done it already, so
suggestions are welcome :).
The end goal is to de-couple the notion of a communication from mail.
Thus alternate modes of transport (XMPP for example) could be used in
future versions of Chandler. As such the classes, in pim.mail that
inherit from DeliveryBase including SMTPDelivery can be factored out
of the code and the CommunicationStatus can be used in its place to
track state of mail communications.
- Add support for a 'created' Modification type. Currently, if you
create a new item, it shows up as "Created by me ...". Then, as
soon as you change something, it says "Edited by me ...". As a nice
to have (IIRC), the design called for it remaining "Created" in
this case, until you switch focus to a different item in the detail
view. I had a first cut at doing this, but it turns out it depends
on some changes I’m making in the recurrence branch.
- UI polish/review detail view changes with Reid/Bryan.
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
Open Source Applications Foundation "chandler-dev" mailing list
http://lists.osafoundation.org/mailman/listinfo/chandler-dev
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
Open Source Applications Foundation "chandler-dev" mailing list
http://lists.osafoundation.org/mailman/listinfo/chandler-dev