Hello,
I’ve had an AppleScript handler I’ve used for some time to save a document as a pdf using GUI scripting and the Save as PDF… command in the standard macOS print dialog.
I’ve recently noticed that there has been some changes to that dialog in Big Sur which has meant I have needed to update my script.
I assume these changes were introduced in macOS 11.0, but I’m not sure. I’m running macOS 11.2 and don’t have any test machines running earlier versions of Big Sur. I know that the print dialog was different in Mojave, which was the last OS I used (I skipped Catalina).
I’d like to know what version introduced the change so I can ensure that it will work properly on other systems. I use this handler as part of other scripts which I distribute to a number of people running various versions of macOS.
Does anybody have any more details or would be willing and able to test on earlier versions of Big Sur?
Basically the issue is that, in 11.2, the macOS print dialog, which is a sheet of a window, contains only one UI element, namely a splitter group. That splitter group then contains all the UI elements which were, on earlier versions of macOS, direct children of the print dialog sheet. So in effect the majority of the UI elements (buttons, menu items, etc) of the print dialog are now grandchildren of the print dialog sheet rather than immediate children.
So if you’re running a version of macOS earlier than 11.2 and later than Mojave, could you please bring up the print dialog and test whether its UI elements are contained within one splitter group or not, and let me know? You should be Abel to do that by running something along the following lines:
set theApp to "" -- the name of the app in which the print dialog has been triggered
tell application "System Events"
tell application process theApp
every UI element of sheet 1 of window 1 -- where sheet 1 of window 1 should be a reference to the print dialog
end tell
end tell
In case it helps understand, my handler is as follows:
on printPDFOfFrontDocument of theApp to theLocation : missing value given fileName:theFileName : "untitled"
-- saves the frontmost document to PDF
-- the location must be in POSIX format (tip: use POSIX path of to convert)
-- #todo: should test whether theLocation given is in POSIX format and, if it's not, should convert it
-- theFileName should not include an extension as one will be added
try
set theFile to missing value -- this will be returned by the handler and, if successful, will be a file object of «class furl»
if theLocation is missing value then set theLocation to POSIX path of (path to desktop folder)
-- first ensure the file name is unique
set theFileName to uniqueFileName for theLocation given fileName:theFileName, extension:".pdf"
repeat -- until user allows accessibility access
try
activate application theApp
-- click the print button (sometimes print shortcut (command-p) doesn't work, particularly it seems in Numbers)
-- send the commands through System Events for GUI scripting
tell application "System Events" to tell application process theApp
if exists menu item "Print Without Preview…" of menu "File" of menu bar item "File" of menu bar 1 then
click menu item "Print Without Preview…" of menu "File" of menu bar item "File" of menu bar 1
set thereIsAPrintPreviewWindow to false
else
click menu item "Print…" of menu "File" of menu bar item "File" of menu bar 1
set thereIsAPrintPreviewWindow to true
end if
end tell
exit repeat
on error msg
activate
display dialog "The most likely reason for this is because you have not granted accessibility permission to " & name of me & ". Please go to System preferences > Security and Privacy > Accesssibility and ensure that " & name of me & " is checked." & return & return & "The other reason might be that your system language is something other than English." & return & return & msg with title "Unable to find the “Print…” button in the file menu" buttons {"Give Up", "Try Again"} default button 2 with icon caution
if button returned of result is "Give Up" then error "Unable to print because the application was not given accessibility permissions, or because the system language is not English." & return & return & msg
end try
end repeat
-- back to System Events
tell application "System Events" to tell application process theApp
-- in Numbers, there is an internal print dialog before the system print dialog appears
if theApp is "Numbers" and thereIsAPrintPreviewWindow then -- wait for the Print Setup formatter to appear
with timeout of 15 seconds
repeat until (button "Print…" of group 1 of window 1) exists
end repeat
click button "Print…" of group 1 of window 1
end timeout
end if -- ap is Numbers
-- wait for the print dialog to appear
with timeout of 60 seconds
repeat until (sheet 1 of window 1) exists
end repeat
end timeout
-- in Big Sur, the print dialog only contains one UI element, namely a splitter group
-- and that splitter group contains the other UI elements
-- not sure what version of Big Sur it was introduced in, but assuming 11.0/10.16 for now
if macOSIsNewerThan("10.16")) then
set PDFButton to first menu button of splitter group 1 of sheet 1 of window 1
else
set PDFButton to first menu button of sheet 1 of window 1
end if
click PDFButton
click menu item 2 of menu 1 of PDFButton -- the save to PDF button
-- wait for the save sheet to appear
with timeout of 60 seconds
repeat until sheet 1 of sheet 1 of window 1 exists
end repeat
end timeout
delay 0.5
tell sheet 1 of sheet 1 of window 1
-- set the file name
if theFileName is not "" then set value of text field 1 to theFileName
delay 0.2
-- set the save in location
keystroke "g" using {command down, shift down}
with timeout of 60 seconds
repeat until sheet 1 exists
end repeat
end timeout
tell sheet 1
-- In macOS Sierra, the location field is a combo box. In earlier versions, it was a text field.
if macOSIsNewerThan("10.12") of OBUtility then
set the value of combo box 1 to theLocation
else
set the value of text field 1 to theLocation
end if
click button "Go" -- to set the location
end tell -- go to sheet
-- Prior to High Sierra, the "Save" button was button 1. In High Sierra, it's no longer button 1, but it is the last UI element
if macOSIsNewerThan("10.13") of OBUtility then
click the last UI element -- to save
-- note: in Mohave 10.14 and newer, it's also button "Save", but it's also the last button so I have not updated the script
else
click button 1 -- to save
end if
end tell -- save dialog
if theApp is "Numbers" and thereIsAPrintPreviewWindow then -- dismiss the Print Setup formatter
try -- in case the save dialog doesn't dismiss in time
with timeout of 15 seconds
-- wait for the save dialog window to be dismissed
repeat until (scroll area "Print Setup formatter" of group 1 of window 1) exists
end repeat
end timeout
if (button "Done" of group 1 of window 1) exists then click button "Done" of group 1 of window 1 -- to dismiss the print setup formatter
-- if there's a timeout error, the handler simply terminates without dismissing the Print Setup formatter – it's not worth worrying about
end try
end if
end tell -- system events
try
set thisFilePath to ((theLocation as text) & theFileName & ".pdf")
set theFile to POSIX file thisFilePath
delay 1
tell application "Finder" to open theFile
end try
try
display notification "PDF saved in " & (theLocation as text) with title "PDF Saved" with subtitle theFileName with sound "Glass"
end try
set theFile to theFile as alias
return a reference to file (theFile as text)
on error
return missing value
end try
-- returns a reference to the newly saved pdf file or missing value on error
end printPDFOfFrontDocument
on macOSVersion()
set theInfo to system info
set theVersion to system version of theInfo
-- when running this script in ScriptDebugger system info still reports macOS 11 Big Sur as version 10.16
-- but when running it from KM (I think) it reports it as 11.x
-- so we'll no longer extract the second part of the version
return theVersion
end macOSVersion
on macOSIsNewerThan(specifiedVersion)
set usersVersion to macOSVersion()
considering numeric strings
return usersVersion is greater than or equal to specifiedVersion
end considering
end macOSIsNewerThan
on uniqueFileName for thisPath as text given fileName:(theFileName as text), extension:theExtension as text
(*
thisPath should be in POSIX format
should check and convert to POSIX format if not already
*)
set i to 1
set theModifier to ""
repeat
set theTestFile to POSIX file (thisPath & theFileName & theModifier & theExtension)
tell application "Finder"
if theTestFile exists then
set theModifier to " v" & i
else
exit repeat
end if
end tell -- Finder
set i to i + 1
end repeat
set theFileName to (theFileName & theModifier) as text -- otherwise it seems that it might be a list
return theFileName
end uniqueFileName
Thanks for any help you can offer.