Whereas OmniOutliner 3 rows and other objects benefit from a
has subtopics property, OmniFocus scripting suffers from the lack of a
has subtasks property.
This is a pity, as efficient (and fast-running) applescripts need to push as much of their logic as possible into WHERE/WHOSE queries, to minimize the volume of slow and costly Apple Event traffic.
It is of course possible to branch on
(count of tasks) > 0, but there is no idiom that I can find which enables us to use a WHERE query to select only those OF tasks which have children. (In OmniOutliner the
has subtopics property makes it easy to do this for rows).
I have given an example below of where I feel the lack of a queryable
has subtopics property, to avoid looping through every task, fetching a list of its potential children, and testing whether the length of the list is more than 0, before going into an attempt at recursive descent. Much more efficient, and cleaner, to delegate this to a lower level through a simple WHERE query.
I have filed a request for the addition of a
has subtasks property through OF
Help > Send Feedback (If you prefer applescripts which run fast, and are simple to write, please feel encouraged to do the same :-)
(This would be particularly helpful, incidentally, for simplifying and speeding up the writing and performance of custom data export scripts, which have to recursively walk the entire data tree).
Code:
-- RETURN A FLATTENED LIST OF ANY (UNCOMPLETED) FLAGGED TASKS
-- OR SUB-TASKS IN A PROJECT
on FlatFlaggedTaskList(oParent)
using terms from application "OmniFocus"
tell oParent
-- ADJUST THE WHERE QUERIES TO MATCH THE PURPOSE
set lstTasks to tasks where (flagged is true) and (completed is false)
-- A HAS SUBTASKS PROPERTY (like HAS SUBTOPIC in OO3 rows) WOULD BE USEFUL:
-- THE FOLLOWING QUERY COULD IMPROVE PERFORMANCE
set lstParentTasks to tasks (**** WHERE HAS SUBTASKS IS TRUE ****)
end tell
-- SOME WASTED ITERATION AND TESTING HERE
repeat with oTask in lstParentTasks
set lstSubTasks to tasks of oTask
if (count of lstSubTasks) > 0 then ¬
set lstTasks to lstTasks & my FlatFlaggedTaskList(oTask)
end repeat
return lstTasks
end using terms from
end FlatFlaggedTaskList
on ProjectList(oParent)
using terms from application "OmniFocus"
tell oParent
-- ADJUST THE WHERE QUERIES TO MATCH THE PURPOSE
set lstProjects to projects where (status is active)
set lstFolders to folders where hidden is false
end tell
repeat with oFolder in lstFolders
set lstProjects to lstProjects & my ProjectList(oFolder)
end repeat
return lstProjects
end using terms from
end ProjectList
on run
tell application id "com.omnigroup.OmniFocus"
set oDoc to default document
set lstProjects to my ProjectList(oDoc)
set lstFlagged to {}
repeat with oProj in lstProjects
set lstFlagged to lstFlagged & my FlatFlaggedTaskList(oProj)
end repeat
set strFlagged to ""
repeat with oTask in lstFlagged
set strFlagged to strFlagged & "-" & tab & name of oTask & return
end repeat
set strMsg to ((count of lstFlagged) as string) & ¬
" flagged tasks in active projects not done:" & return & return & strFlagged
display dialog strMsg with title "Count (uncompleted) flagged tasks in projects"
end tell
tell application "Finder"
set the clipboard to strMsg
end tell
end run