PDA

View Full Version : How can I create a task, using Objective C (or PyObjC)?


Tommy@heltenkelt.se
2008-07-29, 12:47 PM
In AppleScript, a new task can be created like this:

tell front document of application "OmniFocus"
make new inbox task with properties {name: theName}
end tell

But what would be the corresponding message to create a new task in Objective C (or PyObjC)?

Tommy@heltenkelt.se
2008-07-31, 04:09 PM
I have partly solved the problem. With PyObjC a new inbox task object can be created like this:

omnifocus = ScriptingBridge.SBApplication.applicationWithBundl eIdentifier_('com.omnigroup.OmniFocus')

omnifocus.classForScriptingClass_('inbox task').alloc().initWithProperties_({'name': 'Computer created task'})

But, this is a "future OmniFocusInboxTask", and does not show up in the inbox.

How should I do to stop it being future, and start showing up in the present?

curt.clifton
2008-07-31, 05:53 PM
Sorry for the silence on the thread. I haven't tried to automate OF other than with AppleScript, but you seem to have crossed the syntax "bridge", as it were, so maybe I can help now.

What do you mean by "future" OmniFocusInboxTask? A "future" is a fairly arcane programming languages term, but I'm guessing you mean something else.

Wim Lewis
2008-07-31, 09:02 PM
A couple of off-the-cuff ideas, from someone who's not familiar with ScriptingBridge:

Have you looked at the Python "appscript" module? It might be easier to use because there's only one layer of translation going on (Python to the AppleEvents object model)*rather than two (Python to Objective-C to AppleEvents).

My other thought is that you might have to insert the newly created object into a container before it becomes real. Applescript-accessible objects can't exist in a vacuum; they need to be "in" something (possibly just in the application object). ScriptingBridge might be waiting for you to provide the newly created task with a location before it actually sends the AppleEvent to create it.

Tommy@heltenkelt.se
2008-08-01, 11:51 AM
Curt: What do you mean by "future" OmniFocusInboxTask?

The object created by the code above, is described by PyObjC like this:

<future OmniFocusInboxTask with properties { name = "Task name"; }>

I suspect that "future" may be ScriptingBridge's way to indicate that the apple event to create the object is not yet sent. But that's just a theory.


Wim: My other thought is that you might have to insert the newly created object into a container before it becomes real

I think you are right about this. I've tested recreating the code in F-script, and the error message I get there is "object has not been added to a container yet".

But how do I assign it to a container?

In OmniFocus applescript dictionary I found this:

assigned container (item) : Inbox tasks (those contained directly by the document) have a provisionally set container that is made final by the 'compact' command. This allows you to set and get said container. The container must be either a task (not in the inbox or contained by an inbox task), a project or 'missing value'.

But despite trying a lot of different aproaches, I've not been able to make it work.

I'm not 100% sure, but the problem seams to be that

omnifocus.classForScriptingClass_('inbox task').alloc().initWithProperties_({'name': 'Computer created task'})

results in a object that is a ScriptingBridge proxy object. This object as such is unable to respond to messages like compact(), setAssignedContainer_() and addObject_(). Normaly, this would be easy to solve by adding a get(), to get the real object, but for some reason this results in an error.

Maybe it's a cache 22-like bug: To attach the object to a container you need to send a get to it, but since it's not attatched to any container this is not possible....

Another, equally likely, possibility is that I haven't got the sytax quite right.

If anyone has managed to create a new task in OmniFocus, using Objective C, Python, F-script or Ruby, it would be extremely interesting to see the code.

Until then, I might try the applescript in Python workaround Wim suggested.

curt.clifton
2008-08-01, 01:43 PM
A stab in the dark, but is it possible to include the assigned container in the properties list of the original init call?

Tommy@heltenkelt.se
2008-08-01, 02:28 PM
A stab in the dark, but is it possible to include the assigned container in the properties list of the original init call?

Interesting idea, but I can't get that to work.

Tommy@heltenkelt.se
2008-08-01, 02:40 PM
Here is a workaround, using applescript within Python, as Wim suggested:

import os

def createInboxTask(name):
cmd = """osascript<<END
tell front document of application "OmniFocus"
set newTask to make new inbox task with properties {name: "(Placeholder)"}
end tell
END"""
os.system(cmd)

newTask = [task for task in of.application.defaultDocument().inboxTasks() if task.name()=='(Placeholder)'][0]
newTask.setName_(name)
return newTask

Wim Lewis
2008-08-01, 04:26 PM
Actually, I was suggesting using the appscript (http://appscript.sourceforge.net/py-appscript/index.html) module, not using AppleScript. I really like the appscript module.

Re ScriptingBridge, check out the Scripting Bridge Programming Guide for Cocoa section on Creating and Adding Scripting Objects (http://developer.apple.com/documentation/Cocoa/Conceptual/ScriptingBridgeConcepts/UsingScriptingBridge/chapter_3_section_7.html).