Advertisement

Fraser Speirs - January 7th, 2005

> Recent Entries
> Archive
> Friends
> User Info
> www.speirs.org

Links
Photography
April Speirs
Projects
Xjournal
FlickrExport
Feeds
RSS feed
Del.icio.us RSS
Flickr Photos RSS
Reads
Buzz Andersen
Brent Simmons
James D Davidson
bbum
Michael McCracken
Gus Mueller
Other
Amazon.co.uk Wish List
Technorati Profile

January 7th, 2005


09:48 am - Incremental GTD App Hacking
Merlin and I talked a fair bit recently about what we want to see in a mythical perfect application for Getting Things Done.

I had spent some time in Interface Builder trying to make something work, but found it really hard. I had some ideas for particular features I wanted, but I couldn't really bring it together into a coherent whole.

Here's what I came up with originally:

GTD App Mockup: Projects

I wanted better support for the GTD-specific objects in the workflow - next actions and projects. So I put together the following UI for projects:

The things I wanted from this UI were the following:

- A single list of all projects ongoing
- Del.icio.us style tags to support GTD context "work", "home", "calls" etc.
- Links to local files related to project ("project support materials" in GTD terms) (not shown in this screenshot, but was in another rev.)
- Links to the Address Book cards of related people

Another thing I was curious about was critiquing. Years ago, I used to use a tool called ArgoUML. This was a UML design tool with one feature that I don't think I've seen in many apps before or since. It would look at the model you had designed and tell you if you were doing stupid things. For example "This class has no instance variables" or "This class has massive fan-out, consider refactoring".

GTD is a pretty free-form workflow, so it's hard to come up with more than one or two hard rules that you would want to enforce in an application. In fact, the only one that I can think of right now is "every project must have a next action". Anyway, I thought it would be interesting to explore the notion of critiquing your workflow.

Anyway, I really didn't want to write an application for this if I didn't have to. I've recently been getting into OmniOutliner 3, and the final version was just released yesterday. I started wondering to myself if I could implement the features I wanted in this mythical GTD app within OmniOutliner. Here's how I went about it.

Firstly, here's what the outline looks like (click for larger annotated shot):

My GTD Setup in OmniOutliner

1. Use OmniOutliner Professional

The drawer in OO3 Pro acts as the source list in my UI above.

2. Use standard prefixes to mark the type of rows

In OO, I start the text of a row with [NA] if it's a next action. This makes it really easy to pull out all the next actions either with a search for "[NA]" within Outliner or by Applescript. If you're disciplined about this, you can find all your next actions with one line of code:

set nextActions to every row of front document whose topic starts with "[NA]"

I wrote a simple Applescript that will pull out that list of [NA] rows and populate a new document with them:

tell application "OmniOutliner Professional"
  set sourceDocument to front document
  set myDoc to make new document
	
  set nextActions to every row of sourceDocument ¬
    whose topic starts with "[NA]"
	
  repeat with aRow in nextActions
    set props to {topic:(topic of aRow)}
    set theNewRow to make new row ¬
      with properties props ¬
      at end of children of myDoc
  end repeat
end tell


You could also script the addition of the [NA] prefix to selected rows, or write a "Make new Next Action" script which would prompt the user for the text and insert it with [NA] prepended.

This general trick also lets you implement tagging. I use the following general approach:

- In principle every row can be tagged, not just projects or next actions
- To be considered "tagged" a row has a child row whose topic is "Tags" and that child itself has one or more children whose topic starts with "[Tag]" (even my grammar is starting to sound like Applescript!)

Again, it makes a lot of sense to manage this with Applescript. Here's a script called "Tag selected rows":

tell application "OmniOutliner Professional"
  set tagName to text returned of ¬
    (display dialog "Tag selected rows with" ¬
    default answer "newTag" buttons "OK" ¬
    default button "OK")

  set theText to "[Tag] " & tagName
	
  set selectedRows to selected rows of front document
	
  repeat with myparent in selectedRows
    set childlist to (children of myparent whose topic is "Tags")
		
    if (count of childlist) = 0 then
      set tagChild to make new row ¬
        with properties {topic:"Tags"} ¬
        at end of children of myparent
    else
      set tagChild to first item of childlist
    end if
		
    make new row with properties {topic:theText} ¬
      at end of children of tagChild
  end repeat
end tell


What this does is, for every selected row, creates a "Tags" child if one doesn't exist and then add a child to that with the user-provided tag name. As before, you can generate a list of all your tags with a search or a line of Applescript:

set tags to topic of every row of front document whose topic starts with "[Tag]"

And here's the corollary to the above "Tag Selected Rows" script. It's called "Select Tagged Rows":

tell application "OmniOutliner Professional"
  set sourceDocument to front document
  set tag to "[Tag] " & text returned of ¬
    (display dialog "Select which tag?" ¬
    default answer "tag" buttons "OK" default button "OK")

  set tagRows to every row of sourceDocument whose topic is tag
	
  set taggedRows to {}
  repeat with aTagRow in tagRows
    set taggedRow to parent of parent of aTagRow
    set taggedRows to taggedRows & {taggedRow}
  end repeat
	
  select taggedRows
end tell


The smarts in there is that, given that we know that a tagged row has a "Tags" child and that row has n children named "[Tag] *", whenever you find a row beginning "[Tag]" you just ask for the "parent of parent of" the row, and you have the row that we consider "tagged". Neat.

3. Use styles to make row types distinct

I like to use distinct styles to visually attract me to certain things. For example, next actions are a bright red colour. If you create named styles in OO3, you can nicely use the prefix-tagging approach above to style particular types of rows.

For example:

tell application "OmniOutliner Professional"
  set theStyle to first named style of front document ¬
    whose name is "Next Actions"
  set theRows to every row of front document ¬
    whose topic starts with "[NA]"
	
  repeat with r in theRows
    set style of r to theStyle
  end repeat
end tell


4. Drag Address Book cards into OO for "Relevant people"

Whilst you can open Address Book and drag stuff in, it would be nice of OO had a bit more support for this. If Omni incorporated an Address Picker into OO, that would be one less Exposé dance to do.

Also, OO doesn't really allow you do "do" much with an Address Card embedded in an outline. All you can do is really "open" it back into Address Book. It would be great if OO gave you similar options to the little menus in Address Book when you select a person record in that app: 'IM this person', 'Email this person'...etc.

5. Alias files into OO for "Project Support Materials"

This last one is pretty obvious. You can embed links to disk files in an OO outline, which gives you ready-made Project Support Materials lists.

Downloads

You can download these AppleScripts and my example Outline at http://www.mycamera.org.uk/mirror/oogtd.dmg

(8 comments | Leave a comment)

03:01 pm - I don't call that a fair trade.....
At the university dining rooms today:

Fair?

By no stretch of the imagination does 80p for a teaspoonful of instant coffee constitute a "fair" trade. The Guatemalan coffee farmers must be riding around in chrome-plated Escalades at that price....

(10 comments | Leave a comment)


Previous Day [Archive] Next Day

> Go to Top
LiveJournal.com

Advertisement