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

Reply via email to