The Omni Group
These forums are now read-only. Please visit our new forums to participate in discussion. A new account will be required to post in the new forums. For more info on the switch, see this post. Thank you!

Go Back   The Omni Group Forums > OmniFocus > OmniFocus Extras
FAQ Members List Calendar Today's Posts

 
OF Applescript bug: querying for dates with missing values Thread Tools Search this Thread Display Modes
Now that Tim has added the excellent flattened tasks and other related properties to the OF Applescript library in the Sneaky Peek builds, it would be very useful to find all tasks that lack start dates (or perhaps due dates).

Queries of this kind do work well in OO3. If we have an OmniOutliner document with a user-defined date column, we can find any undated rows with code like:

Code:
tell application id "com.omnigroup.OmniOutlinerPro3"
	if (count of documents) < 1 then return
	tell front document
		try
			set lngCol to index of (first column whose type is date)
		on error
			display dialog "There are no date columns in the front document" & return & return & ¬
				"Open or create a document with a user-defined date column, and try again ..."
			return
		end try
		set refUndatedRows to a reference to (rows where value of cell lngCol is missing value)
		set expanded of refUndatedRows to true
		set selected of refUndatedRows to true
		display dialog ((count of refUndatedRows) as string) & " undated rows selected"
	end tell
end tell
In OmniFocus (sneaky peek builds), however, this kind of code currently fails. Lines like:

Code:
set lstNoStart to flattened tasks where start date is missing value
set lstNoDue to flattened tasks where due date is missing value
will generate the error:
Code:
OmniFocus got an error: Can’t make missing value into type date.
The problem seems to be that the underlying data type of a missing value (for any property) is made available in OO3, but is not currently retrievable for several properties in OF.

This is suggested by the output of the code pasted below, in which the specific class of missing values for several OF properties appears to be opaque.

OmniOutliner missing values are all typed:


But several kinds of missing value in OF are not
(including start and due dates):


(Note that an indeterminacy in property sequence when records are coerced to lists seems to have flipped the class string for id and parent task in the second graphic)

Quick test code below:

Code:
on run
	tell application "OmniOutliner Professional"
		tell front document
			set oRow to make new row at end of rows
			set lstProps to my proplist(oRow)
		end tell
	end tell
	
	set lstSelns to {}
	repeat with oProp in lstProps
		if oProp contains "class" then ¬
			if not (oProp begins with "class") then set end of lstSelns to oProp
	end repeat
	choose from list lstProps with title "OMNIOUTLINER Row" with prompt "Data type of all values available ..." default items lstSelns with multiple selections allowed
	
	
	tell application "OmniFocus"
		tell front document
			set oTask to make new task at end of tasks of first project
			set lstProps to my proplist(oTask)
		end tell
	end tell
	
	set lstSelns to {}
	repeat with oProp in lstProps
		if oProp contains "class" then ¬
			if not (oProp begins with "class") then set end of lstSelns to oProp
	end repeat
	choose from list lstProps with title "OMNIFOCUS Task" with prompt "Data type of several values unavailable ..." default items lstSelns with multiple selections allowed
	
	-- BOTH WHERE QUERIES FAIL
	-- (though analogous queries work with OmniOutiner)
	tell application "OmniFocus"
		tell front document
			set lstNoStart to flattened tasks where start date is missing value
			set lstNoDue to flattened tasks where due date is missing value
		end tell
	end tell
end run

------------

-- Build a list of the names and classes of the properties of an object
on proplist(oObj)
	set recProps to (properties of oObj)
	
	-- AND LIST THE CLASSES OF EACH PROPERTY
	set lstProps to recProps as list
	set lstClass to {}
	repeat with oValue in lstProps
		set end of lstClass to class of oValue as string
	end repeat
	
	-- EXTRACT THE NAME OF EACH PROPERTY
	-- BY CONVERTING THE PROPERTY LIST TO A STRING
	-- AND TRANSLATING EACH 4-LETTER CODE TO AN ENGLISH PROPERTY NAME
	set strDelim to text item delimiters
	
	-- Convert the record to a string (by decoding an error message :-)
	set strProps to my Rec2Str(recProps)
	set text item delimiters to ", «"
	set lstItems to text items of strProps
	set text item delimiters to ""
	set first item of lstItems to (characters 3 thru end of first item of lstItems) as text
	
	set lstPropName to {}
	repeat with oItem in lstItems
		-- Extract the class property from the start
		set text item delimiters to "»"
		set lstParts to text items of oItem
		set strClass to "«" & first item of lstParts & "»"
		set oClass to run script strClass
		set end of lstPropName to (oClass as string)
		
		-- Look for any other properties in the rest of the string
		set strRest to item 2 of lstParts
		set text item delimiters to ", "
		set lstRest to text items of strRest
		repeat with strPart in lstRest
			set text item delimiters to space
			set strPossible to first item of text items of strPart
			set text item delimiters to ":"
			set lstCommaParts to text items of strPossible
			if length of lstCommaParts is 2 then
				set strPropName to first item of lstCommaParts
				if length of strPropName > 0 then ¬
					set end of lstPropName to strPropName
			end if
		end repeat
	end repeat
	
	-- COMBINE THE PROPERTY NAMES WITH THE LIST OF CLASSES
	-- (ALLOWING FOR ALTERNATIVE CLASSES IN THE CASE OF THE 'PARENT' PROPERTY)
	
	repeat with iProp from 1 to count of lstPropName
		set (item iProp of lstPropName) to (item iProp of lstPropName) & " - " & item iProp of lstClass
	end repeat
	
	set text item delimiters to strDelim
	
	-- SORT THE LIST ALPHABETICALLY
	set lstPropName to ShellSort(lstPropName)
	return lstPropName
end proplist

-- Convert a record to a string by stealing the interesting part of an error message ...
on Rec2Str(rec)
	-- trigger the simplest error to get the measure of its message
	set recDummy to {a:1} as record
	try
		recDummy as string
	on error strShortMsg
		set strDelim to text item delimiters
		set text item delimiters to {"{a:1}"}
		set lngStart to (length of first text item of strShortMsg) + 1
		set lngEnd to length of last text item of strShortMsg
		set text item delimiters to strDelim
	end try
	-- trigger an informative error and grab its string representation
	-- of the record
	try
		rec as string
	on error strRecordMsg
		set lngEnd to ((length of strRecordMsg) - lngEnd)
		set strRecord to text lngStart thru lngEnd of strRecordMsg
	end try
	return strRecord
end Rec2Str

-- use a shell script to sort a list
on ShellSort(lst)
	set strDelim to text item delimiters
	set text item delimiters to {ASCII character 10} --  linefeed
	set strList to (lst as string)
	set strNew to do shell script "echo " & quoted form of strList & " | sort -f"
	set lstNew to (paragraphs of strNew)
	set text item delimiters to strDelim
	return lstNew
end ShellSort
 
PS There are some other routes to the same result, but they are slow and clumsy, and being able to use missing value correctly would be very much faster and simpler.

This, for example, proves slow ...

Code:
-- set dte to missing value as date
tell application "OmniFocus"
	set today to my TimelessToday()
	tell front document
		count of flattened task
		set refTasksNoStart to a reference to (flattened tasks where not (start date < today) and not (start date ≥ today))
		set refTasksNoDue to a reference to (flattened tasks where not (due date < today) and not (due date ≥ today))
		
		display dialog (((count of refTasksNoStart) as string) & " without start date" & return & return & ¬
			(count of refTasksNoDue) as string) & " without due date" with title ("Total of " & (count of flattened tasks) as string) & " tasks"
	end tell
end tell

on TimelessToday()
	set dte to current date
	date "00:00" of dte
end TimelessToday

Last edited by RobTrew; 2010-07-09 at 04:41 AM.. Reason: adjusted sample code
 
This problem has now been fixed ! (with very impressive speed)

As of Sneaky Peek build revision: 135625, the following now works well:

Code:
tell application "OmniFocus"
	tell front document
		set refTasksNoStart to a reference to (flattened tasks where start date is missing value)
		set refTasksNoDue to a reference to (flattened tasks where due date is missing value)
		set refProjectsNoStart to a reference to (flattened projects where start date is missing value)
		set refProjectsNoDue to a reference to (flattened projects where due date is missing value)
	end tell
end tell
 
 




Similar Threads
Thread Thread Starter Forum Replies Last Post
AppleScript: Populate table with notes & values of an object Macintosh OmniGraffle General 0 2011-01-17 07:22 AM
Some due dates and contexts going missing thewood80 OmniFocus for iPhone 6 2009-07-14 01:42 PM
Missing icon for projects with future start dates jasong OmniFocus 1 for Mac 3 2008-10-20 02:16 PM
Mailaction.applescript missing ? Joe Düring OmniFocus 1 for Mac 8 2008-07-24 05:01 PM
OmniFocus: Querying tasks in Applescript gives odd results RobTrew AppleScripting Omni Apps 0 2008-03-01 02:03 AM


All times are GMT -8. The time now is 04:51 PM.


Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2024, vBulletin Solutions, Inc.