Printing a specific "Numbers" sheet to PDF

Hi all,

I’ve been making the attempt to figure this out this morning to no avail. Code so far is as below. The issue being that I can’t figure out how to select the specific sheet I want to print to PDF.

	tell application "System Events"
		tell process "Numbers"
			keystroke "p" using command down
			tell sheet 1 of window 1
				click menu button "PDF"
				repeat until exists menu 1 of menu button "PDF"
					delay 0.02
				end repeat
				
				click menu item "Save as PDF." of menu 1 of menu button "PDF"
			end tell
		end tell
	end tell

I’ve already done a number of thorough searches both on here and a couple of other sites. The most relevant post was as below.

I’m hoping that there might be a new way of activating a sheet so I can print that one off, that I don’t yet know of.

http://macscripter.net/viewtopic.php?id=39881

Hi,

Numbers.app is able to save files as PDF directly


set destinationFile to (path to desktop as text) & "myNumbersDocument.pdf"
tell application "Numbers"
	save document 1 as "LSDocumentTypePDF" in destinationFile
end tell


Aha. That’s brilliant.

Thanks for that.

Can I specify a specific sheet to print though?

I don’t think so

Ok, cheers Stefan

Hello Stefan

The problem is not to save a document as PDF but to create a PDF displaying a specific sheet.
Save As. and Share doesn’t offer this option.
They apply to the entire document.

To achieve the wanted task, we must select the wanted sheet before triggering print.


(*
Print a specified Numbers sheet in a PDF

CAUTION

The structure of the print process was recently modified but I don't know exactly when.
The property modernVersion allow us to select the script behavior.
If it's set to true, it match the behavior of Numbers 2.3 under 10.8
If it's set to false it match the old behavior.
I will be glad to get infos about config requiring the old behavior to be able to edit the script allowing it to apply automatically the correct process.

KOENIG Yvan (VALLAURIS, France)
2013/01/04
*)

property modernVersion : true

#=====

my activateGUIscripting()

(* 1st parameter define the document to print, here the frontmost one
2nd parameter is the name of the sheet to print
*)
my selectSheet(1, "Feuille 7")
(*
2nd parameter is the name of the resulting PDF.
If you want to use the default name based upon the document name, pass the nil string "" *)
my imprimeDansPDF("Numbers", my dateTimeStamp() & ".pdf")

#=====

on imprimeDansPDF(the_App, nom_pdf)
	
	activate application the_App
	tell application "System Events" to tell application process the_App
		set nbw to count windows
		keystroke "p" using command down
		(*
Wait for the availability of the sheet *)
		repeat
			if exists sheet 1 of window 1 then exit repeat
		end repeat
		# name of menu buttons of sheet 1 of window 1
		--> {"PDF"} but I don't know if it's spelled this way worldwide
		set PDFButton to first menu button of sheet 1 of window 1
		click PDFButton
		# name of menu items of menu 1 of PDFButton
		--> {"Ouvrir le PDF dans Aperçu", "Enregistrer au format PDF.", "Enregistrer au format PostScript.", "Faxer le document PDF.", missing value, "@ PDF-BAT.qfilter", "@ PDF-prépresse CMJN.qfilter", "@ PDF-web.qfilter", "@ PDFX3-ISO.qfilter", "Add PDF to iTunes", "Envoyer le document PDF par courrier électronique", "Enregistrer le document PDF dans le dossier de reçus web", missing value, "Modifier le menu."}
		
		click menu item 2 of menu 1 of PDFButton
		
		if modernVersion then
			(*
The Print interface is no longer a window but a sheet *)
			repeat
				if exists sheet 1 of sheet 1 of window 1 then exit repeat
			end repeat
			tell sheet 1 of sheet 1 of window 1
				if nom_pdf is not "" then set value of text field 1 to nom_pdf
				name of buttons
				--> {"Enregistrer", "Nouveau dossier", "Annuler"}
				click button 1 # ditto keystroke return
			end tell
		else
			(*
Wait for the availability of the Print window *)
			repeat
				if (count windows) > nbw then exit repeat
			end repeat
			# position of text fields of window 1
			--> {position:{875, 190}}
			(*
Set the name of the new PDF *)
			set value of text field 1 of window 1 to nom_pdf
			# name of buttons of window 1
			--> {missing value, missing value, missing value, "Enregistrer", "Nouveau dossier", "Annuler"}
			#click button -3 of window 1 # ditto keystroke return
		end if # modernVersion
	end tell
end imprimeDansPDF

#=====
# (do shell script "date -u +%Y-%m-%d" & character id 160 & "%H%M%S") to get UTC date-time
on dateTimeStamp()
	return (do shell script "date +_%Y%m%d_%H%M%S")
end dateTimeStamp

#=====

(*
most of this handler is from Nigel Garvey
*)
on selectSheet(le_document, la_Feuille)
	script myScript
		property listeObjets : {}
		local maybe, targetSheetRow
		#+++++
		# set log_report to "point 2 : " & (current date) & return
		#+++++
		tell application "Numbers"
			activate
			set le_document to name of document le_document (* useful if the passed value is a number *)
			tell document le_document to set my listeObjets to name of sheets
		end tell # "Numbers".
		
		set maybe to la_Feuille is in my listeObjets
		set my listeObjets to {} # So it will not be saved in the script *)
		if not maybe then
			if my parleAnglais() then
				error "The sheet "" & la_Feuille & "" is unavailable in the spreadsheet "" & le_document & "" !"
			else
				error "La feuille « " & la_Feuille & " » n'existe pas dans le tableur « " & le_document & " » ! "
			end if # my parleAnglais
		end if # not maybe
		
		set maybe to 5 > (system attribute "sys2")
		tell application "System Events" to tell application process "Numbers"
			tell outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of window le_document
				if maybe then (* macOS X 10.4.x
'(value of attributes contains 0)': '(value of attribute "AXDisclosureLevel" is 0)' sometimes works in Tiger, sometimes not.
The only possible instances of 0 amongst the attributes are the disclosure level of a sheet row and the index of the first row, which represents a sheet anyway.
Another possibility is '(value of attribute -1 is 0)', which makes me uneasy. *)
					set targetSheetRow to first row where ((value of attributes contains 0) and (value of first static text is la_Feuille))
				else (* macOS X 10.5.x or higher *)
					set targetSheetRow to first row where ((value of attribute "AXDisclosureLevel" is 0) and ((groups is {}) and (value of first static text is la_Feuille)) or (value of first group's first static text is la_Feuille))
				end if # maybe.
				(*
Handler modified to accomodate sheets requiring a lot of time to get the focus
*)
				tell targetSheetRow to set value of attribute "AXSelected" to true
				set cnt to 0
				repeat (*
Must way that Numbers becomes ready to receive the value *)
					try
						tell targetSheetRow to set value of attribute "AXDisclosing" to true
						exit repeat
					on error
						set cnt to cnt + 1
						delay 0.5 # half a second
					end try
				end repeat
			end tell # outline.
		end tell # "System Events".
		# +++++
		# set log_report to log_report & "point 3, cnt = " & cnt & return & (current date) & return
		# +++++
		tell application "Numbers" to tell document le_document to tell sheet la_Feuille to tell table 1
			with timeout of 20 * 60 seconds (*
WITH this setting, the script will be able to wait 20 minutes for the asked value.
I hope that the document will not be so huge that this delay prove to be too short. *)
				value of cell "A1"
			end timeout
		end tell # "Numbers".
		# +++++
		# set log_report to log_report & "point 4 : " & (current date) & return
		# +++++
		tell application "System Events" to tell application process "Numbers" (*
Do the trick one more time to be sure that the sheet is open *)
			tell targetSheetRow to set value of attribute "AXDisclosing" to true
		end tell # "System Events".
		# +++++
		# return log_report & "point 5 : " & (current date) & return
		# +++++
		(*
End of the modified piece of code
*)
	end script
	run myScript
end selectSheet

#=====

on activateGUIscripting()
	(* to be sure than GUI scripting will be active *)
	tell application "System Events"
		if not (UI elements enabled) then set (UI elements enabled) to true
	end tell
end activateGUIscripting

#=====

Yvan KOENIG (VALLAURIS, France) vendredi 4 janvier 2013 16:09:52

Yvan,

I keep on encountering your posts for a bunch of other questions I have regarding AppleScript, and (I think) you’ve commented on every single one of my posts. So, in advance, thank you very very much for being such an active member.

On a more current note, I’ll have to have a review a bit later of the script you stuck on this post, although it looks as if it has everything I need.

For the moment though, Stefan’s answer was enough. The reason being that I’ll then attempt to separate the relevant pages from the outputted PDF doc.

Thanks again.

Oops

When I copied the selectSheet handler from my library, I failed to include the sentence saying that most of it was written by Nigel Garvey.
It’s now corrected.

Yvan KOENIG (VALLAURIS, France) vendredi 4 janvier 2013 16:55:59