Problem with UI scripting of iCal

I am trying to make a UI script to export iCal calendars - and I can’t get it to work. The script repeatedly exports the first calandar in the list on the left of the iCal window. I expected it to export all 6 of my calendars. Is there a UI command to select the calendar window or to select a calendar? Can you help?

[
set appname to “iCal”
set sdelay to 1
set Prefix to "prefix "
tell application appname to activate
tell application “System Events”
repeat with s from 1 to 6
tell process appname
delay sdelay ----
tell menu bar 1
click menu item “Export.” of menu “File”
delay sdelay -----
keystroke “x” using command down
keystroke Prefix
delay sdelay —
keystroke “v” using command down
delay sdelay —
keystroke “s” using command down
end tell
end tell
delay sdelay —
keystroke (ASCII character 31)
delay sdelay —
end repeat
end tell]



Model: iMac
AppleScript: 1.10.7
Browser: Firefox 3.0.11
Operating System: Mac OS X (10.4)

Give this a try. Note: it’s important that you have the first calendar selected and that the arrow keys will move the selection before running this script.

set calendarNames to {"Home", "Work"}
set myDelay to 1

tell application "iCal"
	activate
	set tempVar to display dialog "Please make sure you have the first calendar selected in iCal and that the arrow keys will move the selection up and down when you press them before you continue!" buttons {"Quit", "Continue"} default button 2 with icon caution
end tell
if button returned of tempVar is "Quit" then return
delay myDelay
tell application "System Events"
	tell process "iCal"
		repeat with i from 1 to (count of calendarNames)
			click menu item "Export." of menu 1 of menu bar item "File" of menu bar 1
			delay myDelay
			keystroke (item i of calendarNames) -- enters the calendar name
			delay myDelay
			keystroke "d" using command down -- puts the calendar on the desktop
			delay myDelay
			click button "Export" of sheet 1 of window "iCal"
			delay myDelay
			if i is not (count of calendarNames) then
				keystroke (ASCII character 31) -- down arrow key
				delay myDelay
			end if
		end repeat
	end tell
end tell

Regulus,
Thank you very much for your model. I have modified it to put a prefix into the saved file name, changed keystroke “d” to “s” and commented out "click button “Export” of sheet 1 of window “iCal”. " Have you any comments on these? The modified script works well. Is there a way of scripting the selection of calendar 1?

--Mostly from Regulus6633, Macscripter.    This exports iCal calendars to the default location
--set calendarNames to {"Home", "Work"}
set calendarNames to {"Birthdays", "Home", "Garden", "Macs", "Oliver", "Sue"}
set myDelay to 1
set Prefix to rdate()
tell application "iCal"
	activate
	set tempVar to display dialog "Please make sure you have the FIRST calendar selected in iCal before you continue!" buttons {"Quit", "Continue"} default button 2 with icon caution
end tell
if button returned of tempVar is "Quit" then return
delay myDelay
tell application "System Events"
	tell process "iCal"
		repeat with i from 1 to (count of calendarNames)
			click menu item "Export." of menu 1 of menu bar item "File" of menu bar 1
			delay myDelay
			keystroke "x" using command down -- cuts calendar name
			keystroke Prefix -- inserts reverse date prefix
			keystroke "v" using command down -- pastes
			delay myDelay
			keystroke "s" using command down -- puts the calendar on the desktop
			delay myDelay
			--	click button "Export" of sheet 1 of window "iCal"
			delay myDelay
			if i is not (count of calendarNames) then
				keystroke (ASCII character 31) -- down arrow key
				delay myDelay
			end if
		end repeat
	end tell
end tell
tell application "iCal" to quit
display dialog "Export of " & (count of calendarNames) & "calendars completed"

--- http://www.attilaacs.de/2007/11/04/copy-date-to-clipboard-applescript/
--- This script treats date as a NUMBER to which months and days can be added
on rdate()
	set theDate to current date
	set {year:y, month:m, day:d} to result
	y * 10000 -- 4 digit year
	result + m * 100 -- 2 digit month
	result + d -- 2 digit day
	set rdate to the (result & " ") as string
end rdate

Browser: Firefox 3.0.11
Operating System: Mac OS X (10.4)

No problem oliverd, happy to help. Here’s some comments for you. They’re not critical comments but since you asked…

The keystroke “d” was there to make sure the desktop folder was where the export would occur. The desktop folder doesn’t always come up as the export path, so that ensures export to the desktop. Try it. Manually start a calendar export. Change the export location to somewhere else like your home folder. The next time you export the home folder will be the location. But if you press cmd-d then it changes to the desktop folder. So that’s why that was there.

The cut and paste isn’t necessary. You already have the calendar name in the list. So if you want to add a prefix just…
keystroke (Prefix & item i of calendarNames)

I tried but couldn’t find a way

If you select a calendar, and then click on for example a particular day on that calendar the script won’t work… even though the first calendar is selected the focus of the cursor isn’t on the calendar name but on a date… therefore the down-arrow keystroke won’t work… so you need to also instruct the user to test the up and down arrows to make sure the cursor focus is correct.

Thanks for the explanations. You have taught me several things I would never have found out by myself!
Thanks again.

I wish I found this thread sooner. I ended writing some GUI scripting to batch export a bunch of calendars. It will start from the first calendar in the side bar and work it’s way down. It either exports to the Desktop or Documents folder, depending on which folder finder selected previously. I should incorporate the:

keystroke “d” using command down – puts the calendar on the desktop

to force it to export to the desktop.

An idea for the next iteration of the script is to let the users select which calendars to export.


-- This script exports multiple calendars to ICS one by one using GUI Scripting

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

set numberOfCalendars to display dialog "How many calendars?" default answer ""

tell application "Calendar"
	activate
end tell

tell application "System Events"
	tell process "Calendar"
		repeat with i from 2 to text returned of numberOfCalendars as number
			
			# Select each calendar
			tell row i of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of window 1
				set selected to true
				delay 1
			end tell
			
			# Click Export from Menu
			tell menu item 1 of menu of menu item "Export" of menu "File" of menu bar 1
				click
				delay 3
			end tell
			
			# Click Export Button from pop up window
			tell button "Export" of sheet 1 of window 1
				click
				delay 1
			end tell
			
			
			if button "Replace" of sheet 1 of sheet 1 of window 1 exists then
				tell button "Replace" of sheet 1 of sheet 1 of window 1
					click
				end tell
				delay 1
			end if
		end repeat
	end tell
end tell

Can’t tell you how many hours I spent with ChatGPT trying to come up with the solution you posted above, thank you.

One slight error with the script is this. I have five calendars, and when I entered 5 in the dialog window that pops up, the script would stop after 4 calendars. Took me a while to stumble upon the solution. I entered 6, and the script completed all five calendars. So, to anybody who finds the script useful, always enter one extra calendar beyond what is shown in Calendar List, and you’ll be good.

Have you developed the script any further?

I have a similar script, that I found someplace (my AppleScript skills are still developing, so I can’t take any credit) that creates a “Calendar Archive.icbu” on the users Desktop, posted below.

activate application "Calendar"
tell application "System Events"
	tell process "Calendar"
		click menu item "Calendar Archive…" of menu 1 of menu item "Export" of menu 1 of menu bar item "File" of menu bar 1
		repeat until exists sheet 1 of window 1
			delay 0.2
		end repeat
		tell sheet 1 of window 1
			keystroke "g" using {command down, shift down}
			repeat until exists sheet 1
				delay 0.2
			end repeat
			tell sheet 1
				set value of text field 1 to "/Users/homer/Desktop/"
				keystroke return
				repeat while exists sheet 1
					delay 0.2
				end repeat
			end tell
			set value of text field 1 to "Calendar Archive"
			click button "Save"
		end tell
	end tell
end tell

delay 3
tell application "Calendar" to quit

here is a slightly modified version using the command “d” keystroke

activate application "Calendar"
tell application "System Events"
	tell process "Calendar"
		click menu item "Calendar Archive…" of menu 1 of menu item "Export" of menu 1 of menu bar item "File" of menu bar 1
		repeat until exists sheet 1 of window 1
			delay 0.2
		end repeat
		tell sheet 1 of window 1
			if exists pop up button "Where:" then
				if value of pop up button "Where:" ≠ "Desktop" then
					keystroke "d" using command down
					delay 0.2
				end if
			end if
			
			set value of text field 1 to "Calendar Archive"
			click button "Save"
		end tell
	end tell
end tell

delay 3
tell application "Calendar" to quit

Yours seems noticeably faster than the one I posted.

I was able to modify the original script posted by “wayland” to do away with the popup window that asks for the number of Calendars, and includes a location to insert the number of Calendars that are present in iCloud (you still need to add 1 to whatever number of Calendars you have). Haven’t figured out that issue yet.


-- This script exports multiple calendars to ICS one by one using GUI Scripting

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

-- Enter number of Calendars (in iCloud) + 1
set numberOfCalendars to 6

tell application "Calendar"
	activate
end tell

tell application "System Events"
	tell process "Calendar"
		repeat with i from 2 to numberOfCalendars
			
			# Select each calendar
			tell row i of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of window 1
				set selected to true
				delay 1
			end tell
			
			# Click Export from Menu
			tell menu item 1 of menu of menu item "Export" of menu "File" of menu bar 1
				click
				delay 3
			end tell
			
			# Click Export Button from pop up window
			tell button "Export" of sheet 1 of window 1
				click
				delay 1
			end tell
			
			
			if button "Replace" of sheet 1 of sheet 1 of window 1 exists then
				tell button "Replace" of sheet 1 of sheet 1 of window 1
					click
				end tell
				delay 1
			end if
		end repeat
	end tell
end tell

delay 3
tell application "Calendar" to quit

Why don’t you fix the counter behavior in the code?

-- Enter number of Calendars (in iCloud)
set numberOfCalendars to 5

and

repeat with i from 2 to (numberOfCalendars + 1)

Thank you. Made both changes and the revised script works perfectly.


-- This script exports multiple calendars to ICS one by one using GUI Scripting

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

-- Enter number of Calendars (in iCloud) + 1
set numberOfCalendars to 5

tell application "Calendar"
	activate
end tell

tell application "System Events"
	tell process "Calendar"
		repeat with i from 2 to (numberOfCalendars + 1)
			
			# Select each calendar
			tell row i of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of window 1
				set selected to true
				delay 1
			end tell
			
			# Click Export from Menu
			tell menu item 1 of menu of menu item "Export" of menu "File" of menu bar 1
				click
				delay 3
			end tell
			
			# Click Export Button from pop up window
			tell button "Export" of sheet 1 of window 1
				click
				delay 1
			end tell
			
			
			if button "Replace" of sheet 1 of sheet 1 of window 1 exists then
				tell button "Replace" of sheet 1 of sheet 1 of window 1
					click
				end tell
				delay 1
			end if
		end repeat
	end tell
end tell

delay 3
tell application "Calendar" to quit

Here is my version with better delays using repeats till exists.


-- This script exports multiple calendars to ICS one by one using GUI Scripting

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

-- Enter number of Calendars (in iCloud) + 1
set numberOfCalendars to 5

tell application "Calendar" to activate

tell application "System Events"
	tell process "Calendar"
		set i to 2
		repeat
			
			# Select each calendar
			tell row i of outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of window 1
				if (name of UI element 1) = "Other" then exit repeat
				set selected to true
				delay 1
			end tell
			
			# Click Export from Menu
			click menu item "Export…" of menu 1 of menu item "Export" of menu 1 of menu bar item "File" of menu bar 1
			repeat until exists sheet 1 of window 1
				delay 0.2
			end repeat
			
			# Click Export Button from pop up window
			tell sheet 1 of window 1
				if exists pop up button "Where:" then
					if value of pop up button "Where:" ≠ "Desktop" then
						keystroke "d" using command down
						delay 0.2
					end if
				end if
				click button "Export"
				repeat 3 times
					delay 0.3
					if button "Replace" of sheet 1 exists then
						click button "Replace" of sheet 1
						exit repeat
					end if
				end repeat
			end tell
			
			set i to i + 1
		end repeat
	end tell
end tell

delay 3
tell application "Calendar" to quit

Yours works equally well, but is significantly faster. The modified one I posted took just under 30 seconds to export all five of my calendars, yours took just a hair over 17 seconds. I think I’ll be using yours, thanks for posting your script.