Appointments, Alarms & To Dos in iCal

Scripting iCal
I use iCal - a lot. I’ve got it reminding me of everything from doctor’s appointments to my favorite TV shows. And it doesn’t hurt that I can sync those alarms to my iPod, so I can be reminded if I’m not at the computer.

But to tell you the truth, I hate using iCal to create my items. Yep, I’m dogging the iCal interface! Having to bounce around fields in the sidebar to set appointment info wasn’t the best choice that Apple could have made, in my opinion. So, being an Applescripter, I wrote my own scripts to set appointments and create to do items.

If you hate the “iCal Experience” as much as I do, you’ll enjoy the scripts in this article. Let’s start with the simplest first, the To Do script.

Prioritize!
Setting To Do items is fairly straightforward - a simple matter of creating a new To Do using the make command. But getting there in style is one of our design goals, so let’s take a look at the script:


global ICactive

set theDate to short date string of (current date)
--Get event Summary
display dialog "To do title:" default answer ""
set myTodo to text returned of the result
--Get date
display dialog "Enter event date:" default answer (theDate as text)
--try
set tdDate to date (text returned of the result)
--end try
--get time
set tdPriority to choose from list {"no priority", "low priority", "medium priority", "high priority"} with prompt "Priority of To Do item:" without multiple selections allowed and empty selection allowed

--check if iCal is active
tell application "System Events"
	if exists application process "iCal" then
		set ICactive to true
	else
		set ICactive to false
	end if
end tell

tell application "iCal"
	set myCals to name of every calendar whose writable is true
	set theCal to (choose from list myCals with prompt "Attach to which calendar?" without multiple selections allowed and empty selection allowed) as text
	tell calendar theCal
		make new todo at end with properties {summary:(myTodo as Unicode text), due date:tdDate, priority:(tdPriority as Unicode text)}
	end tell
	if not ICactive then quit
end tell

First we get all the information we need from the user with a series of dialog boxes, setting default values to make data entry as easy as possible. During this input, we also ask for a priority for the To Do, which we’ll use later.

Now let’s introduce a nicety that a lot of scripts could use - the ability to figure out whether iCal is already running. If not, we then know that we can quit it after we have created our To Do. If so, then we’ll leave it running, assuming that the user has other uses for it. For this functionality we just ask System Events to check and see if the process for iCal exists before we try to address a tell block to iCal.

Next, we check to see which calendars are writable - we can’t add a To Do to any calendar that we’ve subscribed to and can’t write to! Then we ask the user to select one of those calendars.

Finally, we have enough information for our make command! So we make the new To Do and quit iCal (if necessary).

Make the Date!
The Appointment script is arranged in a very similar fashion to the To Do script. We get all the event information from the user, then set the appointment. Here’s the script:


global ABactive, ICactive

set theDate to short date string of (current date)
--Get event Summary
display dialog "Enter event name:" default answer " Appointment"
set eName to text returned of the result
--Get date
display dialog "Enter event date:" default answer (theDate as text)
set eDate to text returned of the result
--get time
display dialog "Enter begin time:" default answer "1:00 pm"
set eTime to text returned of the result
set eStart to date (eDate & space & eTime)
set eEnd to (date (eDate & space & eTime)) + (1 * hours)
--get location
display dialog "Enter event location:" default answer "At Home"
set eWhere to text returned of the result
--get person
display dialog "Enter event person:" default answer "Kevin"
set ePerson to text returned of the result
--Set alarm
display dialog "Display alarm how many hours before?" default answer "24" buttons {"No Alarm", "OK"} default button 2
set {text returned:theText, button returned:theButton} to the result
if theButton is "OK" then
	try
		set alarmTime to (theText as number) * -60
	on error
		set alarmTime to 0
	end try
else
	set alarmTime to 0
end if

--check if Addressbook is active
tell application "System Events"
	if exists application process "Address Book" then
		set ABactive to true
	else
		set ABactive to false
	end if
end tell

tell application "Address Book"
	set anAttendee to name of (first person whose name contains ePerson)
	--if we opened the AB, we'll close it
	if not ABactive then quit
end tell

--check if iCal is active
tell application "System Events"
	if exists application process "iCal" then
		set ICactive to true
	else
		set ICactive to false
	end if
end tell

tell application "iCal"
	set myCals to name of every calendar whose writable is true
	set theCal to (choose from list myCals with prompt "Attach to which Calendar?" without multiple selections allowed and empty selection allowed) as text
	--make event
	set newEvent to make new event at end of events of calendar theCal with properties {summary:eName, start date:eStart, end date:eEnd, location:eWhere}
	make new attendee at end of attendees of newEvent with properties {display name:anAttendee}
	if alarmTime ≠ 0 then make new display alarm at end of display alarms of newEvent with properties {trigger interval:alarmTime}
	--if we opened iCal, we'll close it
	if not ICactive then quit
end tell

This time, we also grab information from the Address Book so that we can add an attendee to the event. To do this, just enter the first name of the attendee in the dialog and the script will find the first person that matches and use that person. If you have several entries with the same first name, that could be a problem and you might want to refine that section for your own purposes. In addition, we ask the user for the number of hours ahead of the event we want to be notified of the event so that we can set an alarm.

That’s all there is to it, really. There has not been a lot written on iCal scripting, but as you can see, it is fairly easy, as scripting goes. You can use these scripts as is from the script menu, or add your own refinements to suit your own needs. One idea: Create an Applescript Studio application that has a nicer interface than iCal to make your appointments.

'Til next time, have fun scripting. Crunch code!