export multiple pages'09 files to 1 PDF in 1 click

Hi everyone,

I have plenty of pages 09 files that I want to merge into a single pdf file… in one click !

With Pages 08 I created a little automator workflow using my “adobe pdf printer”, but unfortunetaly, this workflow doesn’t work anymore with Pages09. Pages 09 doesn’t allow pdf printing from the finder, function that I was using in my workflow.
Does this function work for you guys ?
If not, Apple would have put a limitation deliberately ???! Why ?

I tried the script “batch_export2pdf” design by Yvan Koenig (thanks a lot Yvan !) with Pages09 and Leopard (available here : http://idisk.mac.com/koenigyvan-Public?view=web).
And as I don’t know how applescript works, would anyone have an idea to use Yvan’s script in an automator workflow to adapt it to this process ?

  • ask for files (Pages files)
  • convert (each file) to pdf
  • combine all new pdf to 1 pdf
  • open result pdf file in acrobat

Thanks !

Model: MacBookPro
Browser: Firefox 3.0.10
Operating System: Mac OS X (10.5)

It may help if I directly post Yvan’script !:smiley:

This script is too complex for me.
I need something simple to make the function : export every Pages’09 file given by the finder into a pdf file.
(with Yvan settings that makes exportation with the highest definition)
I’m sure the answer is in this script but I don’t know wich part.
Thanks for any lighting !


--[SCRIPT batch_exportPages2PDF]
(* 
Enregistrer ce script en tant que Script, application ou progiciel.
Exécuter ce script ou 
déposer l'icône d'un dossier sur son icône.
Il ouvre tout document Pages du dossier 
et l' enregistre en fichier PDF  
dans le dossier "wasPages_now_pdf".
Celui-ci peut être sur le bureau
ou dans le dossier "~/Documents".

Si le GUIscripting n'est pas activé 
le script demande votre mot de passe pour l'activer.
Le script récupère le dossier d'exportation par défaut
dans le fichier de préférences de Pages.

Éviter de cliquer durant l'exécution du script
sauf évidemment pour sélectionner le dossier source.

*************

Save the script as a Script, application or application bundle.
Run it or drag and drop a folder icon on its icon.
It opens every Pages's documents stored 
in the folder and save it as PDF file in a folder named "wasPages_now_pdf".
This one may be on the desktop or in the "~/Documents" folder.
according to the property storeOnDesktop.

If GUIscripting is disabled
the script ask for your password to enable it.
The script extract the default export path
from the Pages's preferences file.

Don't click when the script is running.
Except, of course, to select the source folder.

*************

Yvan KOENIG le 20 avril 2008
*)
(* 
Some pieces of code are required because I made a bit of surgery in my system.

version '08 Française : 
application = Pages08,  process = Pages08 
version '08 English : 
application = Pages08English,  process = Pages08English 
version '09 Française : 
application = Pages,  process = Pages 
version '09 English : 
application = Pages09English,  process = Pages09English 

version '08 Française : 
application = Numbers08,  process = Numbers08 
version '08 English : 
application = Numbers08English,  process = Numbers08English 
version '09 Française : 
application = Numbers,  process = Numbers
version '09 English : 
application = Numbers09English,  process = Numbers09English 
*)

(* global properties settings *)

property theApp : "Pages"

property storeOnDesktop : true
(*
true = dest folder will be on Desktop
false = dest folder will be in "~/Documents"
*)
property withSeconds : true
(* 
true = uses seconds in time stamp
false = doesn't use seconds in time stamp *)
property typeNum : 2
(* 
with Pages:  1 = WORD, 2 = PDF, 3 = Txt, 4 = rtf, 5 = rtfd 
with Numbers: 1 = PDF, 2 = Excel, 3 = CSV *)
property quality : 3
(* used for PDF export. 1 = Good, 2 = Better, 3 = Best *)

(* global properties *)

property msg1 : ""
property msg8762 : ""
property msg90 : ""
property msg91 : ""
property msg92 : ""
property msg94 : ""
property msg95 : ""
property msg96 : ""
property msg98 : ""
property msg99 : ""

property rapport : ""
property theExt : ""
property dossierDeStockage : ""
property dossierParDefaut : ""
property localExport : ""
property newExt : ""
property newType : ""
property theButton : missing value
property vernum : missing value
property isOs4 : missing value
property theMenu : missing value
property menuExport : missing value
property permittedUTIs : missing value
property propDefaultStartPoint : missing value
property propDefaultExportFolder : missing value
property nomDuRapport : missing value



on run (* lignes exécutées si on double clique sur l'icône du script application
¢ lines executed if one double click the application script's icon *)
	
	tell application "System Events" to set dossier to choose folder (*
dans un bloc System Events pour avoir un titre de dialogue "localisé" 
¢ in a System Events block to get a localized dialog title. *)
	my commun({dossier})
end run

--=====

on open (sel) (* sel contient une liste d'alias des éléments qu'on a déposés sur l'icône du script (la sélection)
¢ sel contains a list of aliases of the items dropped on the script's icon (the selection) *)
	my commun(sel)
end open

--=====

on commun(elems)
	my initialisations()
	
	try
		repeat with elem in elems
			try
				my exploreTraite(elem as alias, "")
			end try
		end repeat
		
		if rapport = "" then set rapport to msg90 (* 
crée un fichier texte sur le Bureau 
¢ creates a text file on the desktop *)
		set p2d to path to desktop
		set p2r to (p2d as Unicode text) & nomDuRapport
		tell application "System Events"
			if exists (file p2r) then delete (file p2r)
			make new file at end of p2d with properties {name:nomDuRapport}
		end tell
		set rapport to rapport as text
		write rapport to (p2r as alias)
		
	on error MsgErr number NroErr
		if NroErr is not -128 then
			beep 2
			tell application (path to frontmost application as string) to ¬
				display dialog "" & NroErr & " : " & MsgErr with icon 0 buttons {msg99} giving up after 20
		end if -- NroErr is.
		return
	end try
	
	my nettoie()
	if my parleAnglais() then
		my afficheLeMessage("Export done !")
	else
		my afficheLeMessage("Traitement terminé !")
	end if
	
end commun

--=====  

on afficheLeMessage(m)
	beep 1
	tell application (path to frontmost application as string)
		activate
		display dialog m buttons {msg98} default button 1 giving up after 10
	end tell
end afficheLeMessage

--=====

on creeDossierDeStockage(nom) (*
S'il n'existe pas, construit un dossier destination sur le bureau ou dans "~/Documents"
¢ If does not exist, create a destination folder on the desktop or in "~/Documents"
*)
	local dd, dds
	if storeOnDesktop then
		set dd to path to desktop as Unicode text
	else
		set dd to path to documents folder as Unicode text
	end if
	
	if nom ends with ":" then
		set dds to dd & nom
	else
		set dds to dd & nom & ":"
	end if
	(*
dossierDeStockage n'existe pas, on le crée
¢ dossierDeStockage is not available, build it *)
	tell application "System Events" to if not (exists item dds) then make new folder at end of folder dd with properties {name:nom}
	return dds as Unicode text
end creeDossierDeStockage

--=====

on exploreTraite(elem, ptree) (*
elem est un alias
¢ elem is an alias *)
	local elem_, cl_, type_Id
	set elem_ to elem as Unicode text
	tell application "System Events" to tell disk item elem_
		set cl_ to class
		if cl_ is folder then
			set type_Id to ""
		else
			set type_Id to type identifier
		end if
	end tell --  "System Events"
	set cl_ to cl_ as Unicode text
	(* 
son of a bitch, '09 introduced a new UTI !! *)
	if type_Id is in permittedUTIs then (*
C'est un fichier theApp.
¢ It's a theApp document *)
		my TraiteUnDocument(elem_)
	else if cl_ is in {"file package", "«class cpkg»"} then
		set rapport to rapport & msg91 & elem_ & return (*
"Package", Attention, un package EST un dossier "spécial".
¢ Caution, a package IS a "special" folder. *)
	else if cl_ is in {"folder", "«class cfol»"} then
		my ExploreUnDossier(elem_, ptree)
	else
		set rapport to rapport & msg92 & elem_ & return (*  
"Pas un document Pages".
¢ "Not a Pages's document" *)
	end if -- typeId_ is .
end exploreTraite

--=====

on ExploreUnDossier(dossier, ptree)
	local nomElement, cheminElement, C
	repeat with nomElement in list folder dossier without invisibles
		set cheminElement to dossier & nomElement
		tell application "System Events" to set C to name of (dossier as alias)
		my exploreTraite(cheminElement as alias, ptree & C & ":")
	end repeat
end ExploreUnDossier

--=====

on TraiteUnDocument(leCheminOriginal_UniText)
	my export2newExt(leCheminOriginal_UniText as alias, leCheminOriginal_UniText)
end TraiteUnDocument

--=============

on export2newExt(p, leCheminOriginal_UniText) (*
¢ here p is the path as alias *)
	local flag, nom_de_p, nouveauChemin, w, bof, x, p_xport
	try
		tell application theApp
			open p
			set flag to false
			repeat 300 times (*
Attends que le fichier soit réellement ouvert.
¢ Wait until the file is really open *)
				if my getNbWindows() > 0 then
					set flag to true
					exit repeat
				end if
			end repeat
		end tell -- to theApp
		if flag is false then error number 8760 (*
Le fichier n'a pu être ouvert.
¢ The file can't be open. *)
	on error MsgErr number NroErr
		if NroErr = 8760 then
			set rapport to rapport & msg94 & leCheminOriginal_UniText & return
		else
			set rapport to rapport & msg95 & leCheminOriginal_UniText & return
		end if
		return (* can't do the remaining tasks *)
	end try
	
	tell application "System Events" to tell file leCheminOriginal_UniText
		set nom_de_p to name
	end tell -- System Events
	
	if nom_de_p ends with theExt then set nom_de_p to text 1 thru -(2 + (length of theExt)) of nom_de_p
	set nouveauChemin to dossierParDefaut & nom_de_p & "." & newExt
	
	tell application "System Events" to if exists (file nouveauChemin) then set name of file nouveauChemin to nom_de_p & my horoDateur(modification date of file nouveauChemin) & "." & newExt (* name stamped *)
	try
		set {w, bof} to my getFrontWindow()
		if w = "" then error msg8762 number -8762
		tell application "System Events" to tell (first process whose title is theApp)
			click menu item menuExport of menu 1 of menu bar item theMenu of menu bar 1 (* Exporter. *)
			repeat until exists sheet 1 of window w
				delay 0.1
			end repeat
			tell sheet 1 of window w (* sheet containing the buttons PDF, Word, RTF, Standard  or PDF, Excel, CSV*)
				if isOs4 then
					get name of buttons of radio group 1
					click button theButton of radio group 1
				else
					click checkbox theButton of radio group 1
				end if -- isOs4 is true
				
				if newExt is "pdf" then
					delay 0.1
					tell pop up button 1
						click
						click menu item quality of menu 1
					end tell
					delay 0.1
				end if
				
				click button 1 (* Suivant. *)
				repeat until exists button localExport
					delay 0.1
				end repeat
				click button localExport (* Exporter. *)
			end tell -- to sheet.
			
			repeat 20 times
				if exists sheet 1 of window w then
					click button 2 of sheet 1 of window w (*
"Ne pas consulter " dans éventuel rapport d'anomalies
¢ "Don't review" in sheet reporting possible export anomalies *)
					exit repeat
				end if
				delay 0.1
			end repeat
		end tell -- to process . System Events
		
		if dossierDeStockage is not dossierParDefaut then (* we must move the file from folder dossierParDefaut to folder dossierDeStockage *)
			
			set p_xport to dossierDeStockage & nom_de_p & "." & newExt
			
			tell application "System Events" to if exists (file p_xport) then set name of file p_xport to nom_de_p & my horoDateur(modification date of file p_xport) & "." & newExt
			tell application "Finder" to duplicate file nouveauChemin to folder dossierDeStockage (*
			¢ before 10.5, System Events is unable to move *)
			
			my wait4File(p_xport)
			
			tell application "System Events" to if exists file nouveauChemin then delete file nouveauChemin
		end if -- dossierDeStockage is not.
		
		if (theApp starts with "Numbers") and vernum < "2" then (* 
Numbers v1.x ignores 'close window' *)
			my ferme1fenetre()
		else (* 
Saving no is useful when we work with iWork '09 which wish to save every document issued from older version *)
			tell application theApp to close window w saving no
		end if
		
	on error errMsg number errNum
		set rapport to rapport & errMsg & return & msg96 & p & return
	end try
end export2newExt

(* =============
¢ Build a stamp from the modification date_time
*)
on horoDateur(dt)
	local annee, mois, jour, lHeure, lesSecondes, lesMinutes
	set annee to year of dt
	set mois to month of dt as number (* existe depuis 10.4 *)
	set jour to day of dt
	set lHeure to time of dt
	set lesSecondes to (lHeure mod 60)
	set lHeure to round (lHeure div 60)
	set lesMinutes to (lHeure mod 60)
	set lHeure to round (lHeure div 60)
	if withSeconds then
		return "_" & annee & text -2 thru -1 of ("00" & mois) & text -2 thru -1 of ("00" & jour) & "-" & text -2 thru -1 of ("00" & lHeure) & text -2 thru -1 of ("00" & lesMinutes) & text -2 thru -1 of ("00" & lesSecondes)
	else
		return "_" & annee & text -2 thru -1 of ("00" & mois) & text -2 thru -1 of ("00" & jour) & "-" & text -2 thru -1 of ("00" & lHeure) & text -2 thru -1 of ("00" & lesMinutes)
	end if (* 
¢ Here, the stamp is "_YYYYMMDD-hhmm" or "_YYYYMMDD-hhmmss" *)
end horoDateur

(* =============
¢ Take care, the front window may be an Inspector or a dialog one.
*)
on getFrontWindow()
	local namesOfWindows, w, flag
	
	tell application theApp to activate
	tell application "System Events" to tell (first process whose title is theApp)
		set namesOfWindows to name of every window
		repeat with w in namesOfWindows
			if subrole of (get properties of window w) is "AXStandardWindow" then
				set flag to true
				exit repeat
			end if
		end repeat
	end tell
	try
		return {w, flag}
	on error
		return {"", false} (* if there is no window open *)
	end try (*
¢ w is the name of the front document's window *)
end getFrontWindow

(* =============
¢ Wait that the file is completely written on disk 
*)
on wait4File(p) (*
¢ p must be Unicode text *)
	local oldSize, newSize
	set oldSize to 0
	tell application "System Events" to set nnn to name of file p
	repeat
		try
			tell application "System Events" to set newSize to physical size of file p
			if oldSize < newSize then
				set oldSize to newSize
			else
				exit repeat
			end if
		end try
	end repeat
end wait4File

--=====

on activateTheApp()
	local bof, status
	tell application theApp to activate
	if my getStartingStatus() is false then tell application "System Events" to tell (first process whose title is theApp) to keystroke return
	repeat
		set {bof, status} to my getFrontWindow()
		if status then exit repeat
	end repeat
end activateTheApp

(* =============
¢ Close existing open windows *)
on fermeFenetres()
	repeat while my getNbWindows() > 0
		my ferme1fenetre()
	end repeat (*
¢ Now there is no open window *)
end fermeFenetres

--=============

on ferme1fenetre()
	tell application theApp to activate
	tell application "System Events" to tell (first process whose title is theApp) to keystroke "w" using {command down}
end ferme1fenetre

--=============

on getPlistValue(valName, default)
	local thePlist, u
	
	set thePlist to (path to preferences folder as Unicode text) & "com.apple.iWork." & theApp & ".plist"
	tell application "System Events"
		if exists file thePlist then
			tell contents of property list file thePlist
				try
					set u to (value of property list item valName) (* Unicode Text *)
				on error (*
On est là si Pages n'a rien enregistré avec des préférences neuves
¢ Here if Pages never saved with the new preferences file. *)
					set u to default
				end try
			end tell -- to contents of.
		else (*
On est là s'il n'y a pas de fichier de préférences
¢ Here if there is no preferences file. *)
			set u to default
		end if
	end tell -- to system events
	return u
end getPlistValue

--=====

on getStartingStatus() (* 
son of a bitch, I forgot that they don't use the same property name !! *)
	return my getPlistValue(propDefaultStartPoint, false)
end getStartingStatus

--=====

on getDefaultExport() (* 
son of a bitch, I forgot that they don't use the same property name !! *)
	local u
	set u to my getPlistValue(propDefaultExportFolder, "~/Documents")
	set u to (POSIX file (do shell script "echo " & u)) as text
	if u ends with ":" then
		return u
	else
		return (u & ":")
	end if
end getDefaultExport

--===== 

on getNbWindows()
	local C
	tell application theApp to activate
	tell application "System Events" to tell (first process whose title is theApp)
		set C to count of windows
	end tell
	return C
end getNbWindows

--=====

on getVersion()
	try
		tell application theApp to return version
	on error
		return "1"
	end try
end getVersion

--=====

on parleAnglais()
	local z
	try
		tell application theApp to set z to localized string "Cancel"
	on error
		set z to "Cancel"
	end try
	return (z = "Cancel")
end parleAnglais

--=====

on initialisations()
	local titres
	(* theApp,typeNum,vernum, theExt,newExt, newType, theButton, permittedUTIs,propDefaultStartPoint,propDefaultExportFolder,nomDuRapport,isOs4,menuExport, theMenu,msg1,dossierDeStockage ,dossierParDefaut,localExport are global properties *)
	my nettoie()
	tell application "System Events"
		if not (UI elements enabled) then set (UI elements enabled) to true (* 
Active le GUI scripting
¢ Enable GUI scripting *)
	end tell -- to System Events
	
	set vernum to my getVersion()
	
	if theApp starts with "Pages" then (* init properties for Pages *)
		if vernum < "3" then
			if my parleAnglais() then
				error "Requires Pages v3.0 or higher !"
			else
				error "Requiert Pages v3.0 ou ultérieur !"
			end if
		end if -- vernum
		
		set theExt to "pages"
		set {newExt, newType, theButton} to item typeNum of {{"doc", "SLDocumentTypeMSWord", 2}, {"pdf", "SLDocumentTypePDF", 1}, {"txt", "SLDocumentTypePlainText", 4}, {"rtf", "SLDocumentTypeRichText", 3}, {"rtfd", "SLDocumentTypeRichTextBundle", 3}}
		if vernum < "4" then
			set permittedUTIs to {"com.apple.iwork.Pages.Pages"}
		else
			set permittedUTIs to {"com.apple.iwork.Pages.Pages", "com.apple.iwork.pages.sffpages"}
		end if
		set propDefaultStartPoint to "SLDefaultsUseDefaultStartingPoint"
		set propDefaultExportFolder to "SLDocumentDefaultExportDirectory"
		set nomDuRapport to "report_exportFromPages.txt"
		
		if 5 > (system attribute "sys2") then
			set isOs4 to true
			if vernum < "4" then
				set {menuExport, theMenu} to {13, 3}
			else
				set {menuExport, theMenu} to {9, 10}
			end if
		else
			set isOs4 to false
			if vernum < "4" then
				set {menuExport, theMenu} to {13, 3}
			else
				set {menuExport, theMenu} to {8, 10}
			end if
		end if
		
	else if theApp starts with "Numbers" then (* init properties for Numbers *)
		set theExt to "numbers"
		set {newExt, newType, theButton} to item typeNum of {{"pdf", "LSDocumentTypePDF", 1}, {"xls", "LSDocumentTypeExcel", 2}, {"csv", "LSDocumentTypeCSV", 3}}
		if vernum < "2" then (* here if used with Numbers '08 *)
			set permittedUTIs to {"com.apple.iwork.Numbers.Numbers"}
			set propDefaultStartPoint to "LSDefaultsUseDefaultStartingPoint"
		else (* here if used with Numbers '09 *)
			set permittedUTIs to {"com.apple.iwork.Numbers.Numbers", "com.apple.iwork.numbers.sffnumbers"}
			(* son of a bitch, '09 introduced a new property name !! *)
			set propDefaultStartPoint to "ShowStartingPointsForNewDocument"
		end if -- vernum < "2
		
		set propDefaultExportFolder to "LSDocumentDefaultExportDirectory"
		set nomDuRapport to "report_exportFromNumbers.txt"
		
		if 5 > (system attribute "sys2") then
			set isOs4 to true
			if vernum < "2" then
				set {menuExport, theMenu} to {11, 3}
			else
				set {menuExport, theMenu} to {9, 11}
			end if
		else
			set isOs4 to false
			if ernum < "2" then
				set {menuExport, theMenu} to {12, 3}
			else
				set {menuExport, theMenu} to {8, 11}
			end if
		end if
	else (* neither Pages nor Numbers, means Goodbye *)
		if my parleAnglais() then
			error "Treats only Pages and Numbers !" number 8761
		else
			error "Ne gère que Pages et Numbers !" number 8761
		end if
	end if
	
	my prepareMessages()
	
	tell application "System Events" to set titres to title of processes
	
	if theApp is not in titres then my activateTheApp() (* 
Active et ferme la fenêtre du document créé à l'ouverture
¢ Activate and close the doc's window created at opening *)
	my fermeFenetres() (*
¢ Close existing windows *)
	
	my afficheLeMessage(msg1) (*
Éviter de cliquer.
¢ Don't click. *)
	
	tell application theApp to set localExport to localized string "Export"
	set dossierParDefaut to my getDefaultExport() as text
	
	if theApp starts with "Pages" then
		set dossierDeStockage to my creeDossierDeStockage("wasPages_now_" & newExt) (* Unicode text *)
	else
		set dossierDeStockage to my creeDossierDeStockage("wasNumbers_now_" & newExt) (* Unicode text *)
	end if
	
end initialisations

--=====

on nettoie() (*
pour ne pas stocker dans le fichier script
¢ So it will not be stored in the script file *)
	set msg1 to ""
	set msg8762 to ""
	set msg90 to ""
	set msg91 to ""
	set msg92 to ""
	set msg94 to ""
	set msg95 to ""
	set msg96 to ""
	set msg98 to ""
	set msg99 to ""
	set rapport to ""
	set theExt to ""
	set dossierDeStockage to ""
	set dossierParDefaut to ""
	set localExport to ""
	set newExt to ""
	set newType to ""
	set theButton to missing value
	set vernum to missing value
	set isOs4 to missing value
	set theMenu to missing value
	set menuExport to missing value
	set permittedUTIs to missing value
	set propDefaultStartPoint to missing value
	set propDefaultExportFolder to missing value
	set nomDuRapport to missing value
end nettoie

--===== 

on prepareMessages()
	if my parleAnglais() then
		set msg1 to "Don't click when the script is running." & return & "Except, of course, if it ask for."
		
		set msg8762 to "Can't get the window !"
		set msg90 to "No problem during the export process."
		set msg91 to "Package"
		if theApp starts with "Pages" then
			set msg92 to "Not a Pages's document."
			--
			set msg94 to "Pages can't read it."
		else if theApp starts with "Numbers" then
			set msg92 to "Not a Numbers's document."
			--
			set msg94 to "Numbers can't read it."
		end if
		set msg95 to "Not open."
		set msg96 to "Not copied."
		set msg98 to " OK "
		set msg99 to "Oops"
	else
		set msg1 to "Éviter de cliquer durant l'exécution du script" & return & "sauf s'il le demande."
		
		set msg8762 to "Ne trouve pas de fenêtre !"
		set msg90 to "Exportation réussie sans incident."
		set msg91 to "Package"
		if theApp starts with "Pages" then
			set msg92 to "Pas un document Pages."
			--
			set msg94 to "Pages n'a pas pu le lire."
		else if theApp starts with "Numbers" then
			set msg92 to "Pas un document Numbers."
			--
			set msg94 to "Numbers n'a pas pu le lire."
		end if
		set msg95 to "Pas ouvert."
		set msg96 to "Pas copié."
		set msg98 to " Vu "
		set msg99 to " Vu "
	end if
	set msg91 to "### " & msg91 & " ###  "
	set msg92 to "### " & msg92 & " ###  "
	--
	set msg94 to "### " & msg94 & " ###  "
	set msg95 to "### " & msg95 & " ###  "
	set msg96 to "### " & msg96 & " ###  "
end prepareMessages

--=====
(*
One never knows !
on getSetExtension()
	set thePlist to (path to preferences folder as Unicode text) & "com.apple.iWork." & theApp & ".plist"
	tell application "System Events"
		set oldVal to (value of property list item "NSNavLastUserSetHideExtensionButtonState" of property list file thePlist)
		if oldVal  then set (value of property list item "NSNavLastUserSetHideExtensionButtonState" of property list file thePlist) to false
	end tell
	return oldVal
end getSetExtension
*)

--[/SCRIPT]