Sort by date in Palm Desktop 4.2.1

I have, with help from Craig and Kai, the script below that allows me to extract a month’s worth of events from Palm Desktop 4.2.1 and write them out to a text file, with html formatting needed for posting to a web page.


on monthRange(m, y)
	tell {(date (m & " 1 " & y)) - 1}
		set end to beginning + 32 * days + 1
		set end's day to 1
		it
	end tell
end monthRange

set theYear to text returned of (display dialog "Please enter a year:" default answer (current date)'s year)

tell (choose from list {"January", "February", "March", "April", "May", "June", "July", "August", ¬
	"September", "October", "November", "December"} with prompt "Please choose a month:")
	if it is false then error number -128
	set theMonth to item 1
end tell

set {preDate, postDate} to monthRange(theMonth, theYear)
tell application "TextEdit"
	activate
	if not (exists document 1) then
		make new document at beginning with properties {name:"NewGigs"}
		set last paragraph of document 1 to ("<ul>" & theMonth & " " & theYear)
	else
		set last paragraph of document 1 to ("<ul>" & theMonth & " " & theYear)
	end if
end tell

tell application "Palm Desktop"
	set myEvents to events whose start time > preDate and start time < postDate and title contains "gig"
	repeat with i in myEvents
		set gigName to name of i
		set beginTime to start time of i
		set myStuff to {beginTime & " " & gigName} as string
		tell application "TextEdit"
			activate
			set last paragraph of document 1 to ("<li>" & myStuff & "</li>" & return & return)
		end tell
	end repeat
	tell application "TextEdit"
		activate
		set last paragraph of document 1 to ("</ul>")
		set first paragraph of document 1 to ("<ul>" & theMonth & " " & theYear & return)
	end tell
end tell

All is good, except that events are NOT chronological. I found the following script by Nigel that will sort by date…


on sortRecordsbyApptTime(recordList) -- a list of records
	
	-- Make a copy of the list with "sentinal" (place-holder) record at the beginning of it
	set recordList to {item 1 of recordList} & recordList
	
	-- Insertion sort:
	repeat with i from 3 to recordList's length
		-- If a record from the original list has an earlier apptTime than its predecessor
		if recordList's item i's apptTime comes before recordList's item (i - 1)'s apptTime then
			-- Store it and replace it in the list with a non-record
			set r to recordList's item i
			set recordList's item i to missing value
			-- Go back through the list to find a record whose apptTime is the same or earlier,
			-- ending by default at the sentinal if a suitable candidate isn't found
			repeat with j from i - 2 to 1 by -1
				if r's apptTime does not come before recordList's item j's apptTime then exit repeat
			end repeat
			
			-- Make a new list, with the stored record inserted after the one just found and without the non-record
			set recordList to (recordList's items 1 thru j) & {r} & (recordList's records (j + 1) thru -1)
		end if
	end repeat
	
	-- Return a fully sorted list, minus the sentinal
	return the rest of recordList
	
end sortRecordsbyApptTime

…which is great, except my feeble Applescript skills are inadequate to integrate this handler into my script.

If anyone (Kai, Nigel) could show me the way on this one, I would be most appreciative. Seems to me that I need to resort the events in myEvents so that they are chronological by date before I get into the repeat loop, but I just can’t seem to get it.

Thank you,
Todd

Todd:

I took the two scripts and merged them thusly:


on sortRecordsbyApptTime(recordList) -- a list of records
	using terms from application "Palm Desktop"
		-- Make a copy of the list with "sentinal" (place-holder) record at the beginning of it
		set recordList to {item 1 of recordList} & recordList
		-- Insertion sort:
		repeat with i from 3 to recordList's length
			-- If a record from the original list has an earlier apptTime than its predecessor
			if recordList's item i's start time comes before recordList's item (i - 1)'s start time then
				-- Store it and replace it in the list with a non-record
				set r to recordList's item i
				set recordList's item i to missing value
				-- Go back through the list to find a record whose apptTime is the same or earlier,
				-- ending by default at the sentinal if a suitable candidate isn't found
				repeat with j from i - 2 to 1 by -1
					if r's start time does not come before recordList's item j's start time then exit repeat
				end repeat
				-- Make a new list, with the stored record inserted after the one just found and without the non-record
				set recordList to (recordList's items 1 thru j) & {r} & (recordList's records (j + 1) thru -1)
			end if
		end repeat
		-- Return a fully sorted list, minus the sentinal
		return the rest of recordList
	end using terms from
end sortRecordsbyApptTime

on monthRange(m, y)
	tell {(date (m & " 1 " & y)) - 1}
		set end to beginning + 32 * days + 1
		set end's day to 1
		it
	end tell
end monthRange

set theYear to text returned of (display dialog "Please enter a year:" default answer (current date)'s year)

tell (choose from list {"January", "February", "March", "April", "May", "June", "July", "August", ¬
	"September", "October", "November", "December"} with prompt "Please choose a month:")
	if it is false then error number -128
	set theMonth to item 1
end tell

set {preDate, postDate} to monthRange(theMonth, theYear)
tell application "TextEdit"
	activate
	if not (exists document 1) then
		make new document at beginning with properties {name:"NewGigs"}
		set last paragraph of document 1 to ("<ul>" & theMonth & " " & theYear)
	else
		set last paragraph of document 1 to ("<ul>" & theMonth & " " & theYear)
	end if
end tell

tell application "Palm Desktop"
	set myEvents to events whose start time > preDate and start time < postDate and title contains "gig"
	set myEvents to my sortRecordsbyApptTime(myEvents)
	repeat with i in myEvents
		set gigName to name of i
		set beginTime to start time of i
		set myStuff to {beginTime & " " & gigName} as string
		tell application "TextEdit"
			activate
			set last paragraph of document 1 to ("<li>" & myStuff & "</li>" & return & return)
		end tell
	end repeat
	tell application "TextEdit"
		activate
		set last paragraph of document 1 to ("</ul>")
		set first paragraph of document 1 to ("<ul>" & theMonth & " " & theYear & return)
	end tell
end tell

It runs with my data just fine, but I could not find a situation to actually test the sort. Before I added the sort handler, I ran a bunch of tests trying to find a group of events that would be written to TextEdit unsorted, but they always managed to pop in chronological order for me. The good news is that I got the same lists (in the same order) after inserting the sort handler, so at least it does not mess it up at all, and all the data is preserved. Of course, one would expect no less from a Nigel Garvey handler.

Let me know if this is working for you.

Craig,
I run into the same error that I ran into when I tried to merge these 2 scripts:

When I get to…


set recordList to (recordList's items 1 thru j) & {r} & (recordList's records (j + 1) thru -1)

…I get the following error:


Can't get records 2 thru -1 of {event id 580 of application "Palm Desktop", event id 580 of application "Palm Desktop", event id 698 of application "Palm Desktop", missing value, event id 741 of application "Palm Desktop", event id 792 of application "Palm Desktop", event id 798 of application "Palm Desktop", event id 800 of application "Palm Desktop", event id 813 of application "Palm Desktop", event id 838 of application "Palm Desktop", event id 850 of application "Palm Desktop", event id 855 of application "Palm Desktop"}.

It seems it chokes on the (recordLists’s records (j + 1) thru -1) part of the script…

Hmm…
Todd

Todd:

I see what you mean. I was afraid of something like this, since I could not find a month of event in my database that were not already sorted. Perhaps you were correct in cursing the Palm software after all; I believe that it simply cannot read the list when the [missing value] term is encountered.

I believe this can be overcome. The only information the sort function needs is the event id number and the start time. If we build a handler that takes your list of gigs and builds a new set of generic records with only the id and the dates, hopefully the sort handler will not choke. Then another handler could convert the sorted list back into a list that the Palm software will like, and you can build the TextEdit document.

Give me a day or two, unless Nigel or someone peruses this thread first.

Hi guys.

I haven’t had time to go through this in any detail but, at first glance, it looks like there might be a simple class/terminology issue. Nigel’s original sort routine was apparently intended for records, while you seem to be sorting a list of events.

I may get a chance later to look at this more closely - but, in the meantime, have you tried something like this?

set recordList to (recordList's items 1 thru j) & {r} & (recordList's items (j + 1) thru -1)

Kai,
First of all, thank you for taking time to look at this. You and Craig have been most helpful so far.

I tried this and below is a snippet from the Event Log:


tell application "Palm Desktop"
	get every event whose start time > date "Tuesday, January 31, 2006 11:59:59 PM" and start time < date "Wednesday, March 1, 2006 12:00:0 AM" and title contains "gig"
		{event id 580, event id 698, event id 708, event id 741, event id 792, event id 793, event id 794, event id 798, event id 800, event id 813, event id 838, event id 850, event id 855, event id 65618}
	get apptTime of event id 698
		"Palm Desktop got an error: Can't get apptTime of event id 698."

I tried changing apptTime to start time, since Palm Desktop can address that property. Upon running the script, I get the following:


tell application "Palm Desktop"
	get every event whose start time > date "Tuesday, January 31, 2006 11:59:59 PM" and start time < date "Wednesday, March 1, 2006 12:00:0 AM" and title contains "gig"
		{event id 580, event id 698, event id 708, event id 741, event id 792, event id 793, event id 794, event id 798, event id 800, event id 813, event id 838, event id 850, event id 855, event id 65618}
	get start time of event id 698
		date "Monday, February 13, 2006 7:00:0 PM"
	get start time of event id 580
		date "Friday, February 10, 2006 2:30:0 PM"
	get start time of event id 708
		date "Monday, February 6, 2006 5:00:0 PM"
	get start time of event id 698
		date "Monday, February 13, 2006 7:00:0 PM"
	get start time of event id 708
		date "Monday, February 6, 2006 5:00:0 PM"
	get start time of event id 580
		date "Friday, February 10, 2006 2:30:0 PM"
	get start time of event id 708
		date "Monday, February 6, 2006 5:00:0 PM"
	get start time of event id 580
		date "Friday, February 10, 2006 2:30:0 PM"
		"Can't get start time of missing value."

I’m a bit unsure of what’s going on (and what’s missing)…all the “gig” events have start time’s, so that doesn’t seem to be it.

Cornfused,
Todd

Yeah - sorry, Todd. I realised just after posting that the missing value wouldn’t get filtered out when using ‘items’. Since I don’t suppose ‘events’ will work in place of ‘items’, we need a slightly different approach. I’m in the middle of something else right now, but I’ll try to take a look at it shortly.

This is completely cobbled together and untested - but might be worth trying. I thought we could stick with an adaptation of a Garvey-based sort routine (since he does them so well). Most of the rest is what Craig and Todd posted earlier. (Come to think of it, I’ve contributed very little here at all…) :slight_smile:

to sortEvents(a, l, r) (* with thanks to Nigel Garvey, Arthur Knapp & Serge Belleudy-d'Espinose *)
	script o
		property p : a
	end script
	set i to l
	set j to r
	using terms from application "Palm Desktop"
		set v to o's p's item ((l + r) div 2)'s start time
		repeat while (j > i)
			repeat while (o's p's item i's start time < v)
				set i to i + 1
			end repeat
			repeat while (o's p's item j's start time > v)
				set j to j - 1
			end repeat
			if (not i > j) then
				set o_s_p_s_item_i to o's p's item i
				set o's p's item i to o's p's item j
				set o's p's item j to o_s_p_s_item_i
				set i to i + 1
				set j to j - 1
			end if
		end repeat
	end using terms from
	if (l < j) then sortEvents(o's p, l, j)
	if (r > i) then sortEvents(o's p, i, r)
end sortEvents

on monthRange(m, y)
   tell {(date (m & " 1 " & y)) - 1}
       set end to beginning + 32 * days + 1
       set end's day to 1
       it
   end tell
end monthRange

set theYear to text returned of (display dialog "Please enter a year:" default answer (current date)'s year)

tell (choose from list {"January", "February", "March", "April", "May", "June", "July", "August", ¬
   "September", "October", "November", "December"} with prompt "Please choose a month:")
   if it is false then error number -128
   set theMonth to item 1
end tell

set {preDate, postDate} to monthRange(theMonth, theYear)
tell application "TextEdit"
   activate
   if not (exists document 1) then
       make new document at beginning with properties {name:"NewGigs"}
       set last paragraph of document 1 to ("<ul>" & theMonth & " " & theYear)
   else
       set last paragraph of document 1 to ("<ul>" & theMonth & " " & theYear)
   end if
end tell

tell application "Palm Desktop"
   set myEvents to events whose start time > preDate and start time < postDate and title contains "gig"
   my sortEvents(myEvents, 1, count myEvents)
   repeat with i in myEvents
       set gigName to name of i
       set beginTime to start time of i
       set myStuff to {beginTime & " " & gigName} as string
       tell application "TextEdit"
           activate
           set last paragraph of document 1 to ("<li>" & myStuff & "</li>" & return & return)
       end tell
   end repeat
   tell application "TextEdit"
       activate
       set last paragraph of document 1 to ("</ul>")
       set first paragraph of document 1 to ("<ul>" & theMonth & " " & theYear & return)
   end tell
end tell

Edit: script modified to address issue raised by imadrummer (below).

Kai,
Correct…events didn’t work. I’ve got to go out for the evening (my 14 year old son has a gig tonite, not me)…I’ll give it a look in the morning.

Thanks,
Todd

Kai,
Well, it gave a valiant effort…but, to no avail, I’m sorry. Below are the results of the Event Log:


tell current application
	current date
		date "Tuesday, January 24, 2006 5:28:53 PM"
	display dialog "Please enter a year:" default answer 2006
		{text returned:"2006", button returned:"OK"}
	choose from list {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} with prompt "Please choose a month:"
		{"February"}
end tell
tell application "TextEdit"
	activate
	exists document 1
		true
	set last paragraph of document 1 to "<ul>February 2006"
end tell
tell application "Palm Desktop"
	get every event whose start time > date "Tuesday, January 31, 2006 11:59:59 PM" and start time < date "Wednesday, March 1, 2006 12:00:0 AM" and title contains "gig"
		{event id 580, event id 698, event id 708, event id 741, event id 792, event id 793, event id 794, event id 798, event id 800, event id 813, event id 838, event id 850, event id 855, event id 65618}
	sortEvents({event id 580, event id 698, event id 708, event id 741, event id 792, event id 793, event id 794, event id 798, event id 800, event id 813, event id 838, event id 850, event id 855, event id 65618}, 1, 14)
		"Palm Desktop got an error: Can't continue sortEvents."

Todd

Sorry, Todd. That’s what happens when you try and script without testing. Only for the brave or (in my case) the foolhardy. :wink:

I’ve modified the script above to fix what I believe was the problem. Perhaps you could try it again?

Kai/Craig/Nigel,
You guys ARE THE DUDES!!! This worked…and thank you so much!!! I will let this one be a learning experience for me to grow in my scripting knowledge so that I can share the wealth!!!

Thanks again,
Todd

Thanks for people’s kind words about the sorts. But I should point out that Arthur Knapp did most of the leg work on them. I just collaborated with him on some speed improvements (none of which appear above!). :wink:

I couldn’t help with the Palm Desktop events as I don’t have that application. But here’s a tiny contribution. If the script’s only likely to be handling a few events, an insertion sort would make a good alternative to the Quicksort:

on sortEvents(a, l, r)
	script o
		property p : a
	end script
	using terms from application "Palm Desktop"
		repeat with i from l + 1 to r
			set thisEvent to o's p's item i
			set thisTime to thisEvent's start time
			repeat with j from i to l by -1
				if (j > l) and (thisTime comes before o's p's item (j - 1)'s start time) then
					set o's p's item j to o's p's item (j - 1)
				else
					set o's p's item j to thisEvent
					exit repeat
				end if
			end repeat
		end repeat
	end using terms from
end sortEvents

Nigel,
Yes, your addition works just fine…I didn’t notice any “major” speed increases, but it, at least, makes the code a bit leaner…

Thank you,
Todd

My apologies for that, Nigel. That version was the only one I could find knocking about. I didn’t want to attempt a reworking in the time I had available, nor insert one of my home-grown affairs (even though one or two of them are quite respectable) - so I stuck to to a light customisation of what I had. Your revision looks a good deal healthier. :wink:

All,
Found a bug in this script (in MY portion) that would cause the first event that got written to the TextEdit file to get overwritten by the date and year unordered list opening tag

    . Below is a corrected version of the final script, which is working well. At some point, I think I might want to be able to trim down some of the text that gets gathered from the start time property…I’ll try and tackle that another day.

    Thanks again,
    Todd


on sortEvents(a, l, r)
	script o
		property p : a
	end script
	using terms from application "Palm Desktop"
		repeat with i from l + 1 to r
			set thisEvent to o's p's item i
			set thisTime to thisEvent's start time
			repeat with j from i to l by -1
				if (j > l) and (thisTime comes before o's p's item (j - 1)'s start time) then
					set o's p's item j to o's p's item (j - 1)
				else
					set o's p's item j to thisEvent
					exit repeat
				end if
			end repeat
		end repeat
	end using terms from
end sortEvents
on monthRange(m, y)
	tell {(date (m & " 1 " & y)) - 1}
		set end to beginning + 32 * days + 1
		set end's day to 1
		it
	end tell
end monthRange

set theYear to text returned of (display dialog "Please enter a year:" default answer (current date)'s year)

tell (choose from list {"January", "February", "March", "April", "May", "June", "July", "August", ¬
	"September", "October", "November", "December"} with prompt "Please choose a month:")
	if it is false then error number -128
	set theMonth to item 1
end tell
tell application "TextEdit"
	activate
	if not (exists document 1) then
		make new document at beginning with properties {name:"NewGigs"}
	end if
	set first paragraph of document 1 to ("<ul>" & theMonth & " " & theYear & return & return)
end tell
set {preDate, postDate} to monthRange(theMonth, theYear)
tell application "Palm Desktop"
	set myEvents to events whose start time > preDate and start time < postDate and title contains "gig"
	my sortEvents(myEvents, 1, count myEvents)
	repeat with i in myEvents
		set gigName to name of i
		set beginTime to start time of i
		set myStuff to {beginTime & " " & gigName} as string
		tell application "TextEdit"
			activate
			set last paragraph of document 1 to ("<li>" & myStuff & "</li>" & return & return)
		end tell
	end repeat
	tell application "TextEdit"
		activate
		set last paragraph of document 1 to ("</ul>")
	end tell
end tell

Todd:

To play with the date text, you would start with this line of yours:

 set beginTime to start time of i

That’s where you have it set up to write the date to your TextEdit document, and it is currently writing out the whole, long date string. If you want some thing like 1/1/06, you would rewrite it thusly:

 set beginTime to short date string of  (start time of i)

And really, the sky is the limit on how you can put that string together, depending on what you want. This is great part about that item being a property. Applescript offers you a good number of parts within that date property so that you can use as much or as little of it that you would like.

This would actually be a good exercise for you. Decide on which parts you want (month, day, year, etc.) and build the string for your variable [beginTime] just the way you want it. I don’t know if there is a post out there with more detailed explanations of all the different parts to the date property, but you found Nigel’s sort routine just fine, so give it a try and let us know what you come up with.

Craig,
Yes, this WILL be a great learning exercise for me…thank you very much for your help and suggestions…

Todd

Craig,
Interesting that, when I insert your suggestion and run the script, I get the following error message:

“Palm Desktop got an error: Can’t get short date string of start time of event id 850. Access not allowed.”

However, when I change the script from…


set myEvents to events whose start time > preDate and start time < postDate and title contains "gig"

…to…


set myEvents to properties of events whose start time > preDate and start time < postDate and title contains "gig"

it works, AND runs MUCH faster!

Todd

Todd:

Nice work! Have you decided just how you want to play with the date property yet? I would like to see your final script when you do.