looping over a changing number of files

Hi,

I need a simple script that helps me sort through and close all my open Preview windows. However, there is an indexing problem with the following snippet [1]. I get indexing errors after closing files [2], so perhaps by closing the files, the indices are changing within the loop? I tried checking for existence of the files (commented out), but I also get errors. I’d appreciate any tips.

Thanks,
Ben

[1]


tell application "Preview"
	set windowCount to number of windows
	repeat with x from 1 to windowCount
		#		if exists (window x) then
		set docName to (name of document of window x)
		set dialog_reply to display dialog docName buttons {"Keep", "Close"}
		if (button returned of dialog_reply is "Close") then
			close window x
		end if
		#		end if
	end repeat
end tell

[2] error “Preview got an error: Can’t get window 5. Invalid index.” number -1719 from window 5

Model: Macbook Pro
AppleScript: 2.11 (208)
Browser: Safari 605.1.15
Operating System: macOS 10.14

The number of window count changes after you close each window.
i.e Lets say you have 5 windows. when you close any window, right after that,there is no window 5
only windows 1 thru 4

Your way will break when you get just past the hallway point.
(you keep incrementing your count, and the number of windows keeps decreasing)

tell application "Preview"
	set windowCount to number of windows
	repeat with x from 1 to windowCount
		#		if exists (window x) then
		set docName to (name of document of window 1) -- always working on first window
		set dialog_reply to display dialog docName buttons {"Keep", "Close"}
		if (button returned of dialog_reply is "Close") then
			close window 1
		end if
		#		end if
	end repeat
end tell

I guess that looping starting from the last window to the first one would behave correctly:

tell application "Preview"
	set windowCount to number of windows
	repeat with x from windowCount to 1 by -1
		#		if exists (window x) then
		set docName to (name of document of window x)
		set dialog_reply to display dialog docName buttons {"Keep", "Close"}
		if (button returned of dialog_reply is "Close") then
			close window x
		end if
		#		end if
	end repeat
end tell

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mardi 30 juin 2020 00:52:08

or like mine, just keep doing the “1st” window

I apologize but your proposal doesn’t work.

 don't click here, it's a log history
tell application "Preview"
	count every window of current application
		--> 4
	get name of document of window 1
		--> "s-l1600.jpg"
end tell
tell application "Script Editor"
	display dialog "s-l1600.jpg" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
end tell
tell application "Preview"
	get name of document of window 1
		--> "s-l1600.jpg"
end tell
tell application "Script Editor"
	display dialog "s-l1600.jpg" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
end tell
tell application "Preview"
	get name of document of window 1
		--> "s-l1600.jpg"
end tell
tell application "Script Editor"
	display dialog "s-l1600.jpg" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
end tell
tell application "Preview"
	get name of document of window 1
		--> "s-l1600.jpg"
end tell
tell application "Script Editor"
	display dialog "s-l1600.jpg" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
end tell

But you may use the alternate code:

tell application "Preview"
	repeat with docName in (get name of windows)
		tell me to set dialog_reply to display dialog docName buttons {"Keep", "Close"}
		if (button returned of dialog_reply is "Close") then
			close window docName
		end if
	end repeat
end tell
Don't click, here is a log history
tell application "Preview"
	get name of every window
		--> {"s-l1600.jpg", "H2597-L46716742.jpg", "Klicka för att stänga fönstret-1.jpeg", "gerbino oiseaux.jpeg"}
end tell
tell application "Script Editor"
	display dialog "s-l1600.jpg" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
end tell
tell application "Preview"
	close window "s-l1600.jpg"
end tell
tell application "Script Editor"
	display dialog "H2597-L46716742.jpg" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
	display dialog "Klicka för att stänga fönstret-1.jpeg" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
	display dialog "gerbino oiseaux.jpeg" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
end tell
tell application "Preview"
	close window "gerbino oiseaux.jpeg"
end tell

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mardi 30 juin 2020 02:25:13

Hi,

Thank you for your feedback.
Indeed, the second solution of Yvan Koenig has the intended behavior.
(The first two solutions using the windowCount did not work properly.)

Best,
Ben

What was wrong with the proposal of message #3?

I tested it and it worked.

Don't click, here is a log history

tell application "Preview"
	count every window of current application
		--> 5
	get name of document of window 5
		--> "part_taxe_habitation.pdf"
	display dialog "part_taxe_habitation.pdf" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
	get name of document of window 4
		--> "H2597-L46716742.jpg"
	display dialog "H2597-L46716742.jpg" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
	get name of document of window 3
		--> "ligne droite.jpeg"
	display dialog "ligne droite.jpeg" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
	close window 3
	get name of document of window 2
		--> "soucoupe YK.png"
	display dialog "soucoupe YK.png" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
	close window 2
	get name of document of window 1
		--> "MOJAVE USERS, PLEASE READ ME FIRST !.pdf"
	display dialog "MOJAVE USERS, PLEASE READ ME FIRST !.pdf" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
end tell

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mercredi 1 juillet 2020 11:53:02

I tried alternating between keeping and closing documents,
and I got the error :

with result :

Curious.

(1) it’s the way you grabbed the name in your original code
(2) In your original message you wrote that you got : error “Preview got an error: Can’t get window 5. Invalid index.” number -1719 from window 5
which, if I read correctly, mean that you didn’t got this error with windows 1, 2, 3, 4.

(3) I re-tested with windows created from the content of the clipboard and was never saved untitled, untitled 2 … and it worked with no problem.

May you tell us what was the content of this window with no document (possibly with a screenshot) ?

Of course we may replace

set docName to (name of document of window x)

by

set docName to (name of window x)

but I wish to understand why the first one failed.
In the Preview’s AppleScript dictionary, the property document of a window is not described as optional.

We may be facing a problem specific to 10.14 but if it’s, I don’t understand why it didn’t face with your original script.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mercredi 1 juillet 2020 15:52:14

I am trying to see what this window is that has a non-existent document. But I do not see anything.

However, the script from reply #3 does work if I pop up a confirmation window after the close happens, as follows. Maybe there is some time lag before the window or document is closed such that it gets confused, and by adding this extra step, the confusion is avoided ?

This code works :


tell application "Preview"
	set windowCount to number of windows
	repeat with x from windowCount to 1 by -1
		#        if exists (window x) then
		set docName to (name of document of window x)
		set dialog_reply to display dialog docName buttons {"Keep", "Close"}
		if (button returned of dialog_reply is "Close") then
			close window x
		end if
		display dialog button returned of dialog_reply
		#        end if
	end repeat
end tell

Puzzling.
I retried with the script of message #3 and it behaved flawlessly.

Don't click, this is a log history

tell application "Preview"
	count every window of current application
		--> 6
	get name of document of window 6
		--> "Sans titre"
	display dialog "Sans titre" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
	close window 6
	get name of document of window 5
		--> "part_taxe_habitation.pdf"
	display dialog "part_taxe_habitation.pdf" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
	close window 5
	get name of document of window 4
		--> "2014-11-20T13.56.00 Gerbino.png"
	display dialog "2014-11-20T13.56.00 Gerbino.png" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
	close window 4
	get name of document of window 3
		--> "2011 026.tiff"
	display dialog "2011 026.tiff" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
	close window 3
	get name of document of window 2
		--> "a15d8c10a9beb0418404111776af251fab68527e2d80890579f1806a46dcbd2f.jpg"
	display dialog "a15d8c10a9beb0418404111776af251fab68527e2d80890579f1806a46dcbd2f.jpg" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
	get name of document of window 1
		--> "a213e52fbc66e4068bbc3796b0a302259d42c70da60c58e0ca2d654c63ac95d7.jpeg"
	display dialog "a213e52fbc66e4068bbc3796b0a302259d42c70da60c58e0ca2d654c63ac95d7.jpeg" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
end tell

and with the script of message #5 I got

tell application "Preview"
	get name of every window
		--> {"Sans titre", "2011 026.tiff", "part_taxe_habitation.pdf (page 1 sur 15)", "2014-11-20T13.56.00 Gerbino.png", "a213e52fbc66e4068bbc3796b0a302259d42c70da60c58e0ca2d654c63ac95d7.jpeg", "a15d8c10a9beb0418404111776af251fab68527e2d80890579f1806a46dcbd2f.jpg"}
end tell
tell application "Script Editor"
	display dialog "Sans titre" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
end tell
tell application "Preview"
	close window "Sans titre"
end tell
tell application "Script Editor"
	display dialog "2011 026.tiff" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
end tell
tell application "Preview"
	close window "2011 026.tiff"
end tell
tell application "Script Editor"
	display dialog "part_taxe_habitation.pdf (page 1 sur 15)" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
end tell
tell application "Preview"
	close window "part_taxe_habitation.pdf (page 1 sur 15)"
end tell
tell application "Script Editor"
	display dialog "2014-11-20T13.56.00 Gerbino.png" buttons {"Keep", "Close"}
		--> {button returned:"Close"}
end tell
tell application "Preview"
	close window "2014-11-20T13.56.00 Gerbino.png"
end tell
tell application "Script Editor"
	display dialog "a213e52fbc66e4068bbc3796b0a302259d42c70da60c58e0ca2d654c63ac95d7.jpeg" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
	display dialog "a15d8c10a9beb0418404111776af251fab68527e2d80890579f1806a46dcbd2f.jpg" buttons {"Keep", "Close"}
		--> {button returned:"Keep"}
end tell

which, logically, is exactly the same behavior.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mercredi 1 juillet 2020 18:05:56

Both of Yvan’s scripts work for me on Catalina. A number of macOS apps do not handle window management well (most notably Script Editor) and so the OP may want to try the following.

tell application "Preview"
	
	set allDocuments to the name of every document
	
	repeat with aDocument in allDocuments
		display dialog aDocument buttons {"Cancel", "Keep", "Close"} default button 2
		if button returned of result is "Close" then close document aDocument
	end repeat
	
	if (count documents) = 0 then quit -- disable if desired
	
end tell

@peavine
The OP wrote that the script in message #5 which grabbed the names as (name of windows) worked on its side.
The only problem is with the script in message #3 which was designed to allowing us to close or keep the windows starting form the last one.

With this one, assuming that we start with 5 windows
index 1 – docA
index 2 – docB
index 3 – docC
index 4 – docD
index 5 – docE

We start by grabbing the name of document of window 5, decide to keep it or close it
Then we do the same with window at index 4
and so on.

When I read the posted error message, my first reaction was : oops, maybe if a window display a content which was never saved, maybe it has no document available.
So I copied a portion of a picture, asked Preview to create a window with the content of the clipboard and ran the script. No luck the idea was wrong. the window was proposed with the name “Untitled” and, when I clicked upon the Close button I was politely asked if I wanted to save its content in a file.
It’s why I asked for precision about the window which urged the script to return :
error “Preview got an error: Can’t get document of window 2.” number -1728 from document of window 2

Alas the OP was unable to give the wanted details and I am really puzzled by this odd behavior.
I can’t guess that the OP invented this error message
but I also can’t guess which window may had issue it.

Your proposal is fine which give the ability to exit the loop by clicking the Cancel button but, alas, it doesn’t bring light upon the “mysterious” window.

Don’t worry, it’s not the cause of my insomnia.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) jeudi 2 juillet 2020 00:37:11

Thanks. I missed that.

I here drew attention to post #3 of this topic, which works unstable for the OP or does not work at all. I was also getting the error mentioned by the OP, but only on some attempts where I was opening multiple image files at the same time. So I added the countWindows variable to the end of the repeat loop to keep track of the windows.

And now the reason for the instability of the code was found - Preview simply does not close the windows immediately, so references to 2 closed windows are still keeped by script… The script keeps references to the last 2 deleted windows, but these windows no longer exist and, accordingly, the documents of window 2 and window 1. That is, this is a problem of synchronizing the actions of the script and Preview.app


tell application "Preview"
	set windowCount to number of windows
	repeat with x from windowCount to 1 by -1
		set docName to (name of document of window x)
		set dialog_reply to display dialog docName buttons {"Keep", "Close"}
		if (button returned of dialog_reply is "Close") then
			close window x
		end if
		-- ADDED by me
		set windowsCount to count windows -- Returns 2 after all windows is closed!!!
	end repeat
end tell

The workaround to fix this problem is add automated delay:


tell application "Preview"
	set windowCount to number of windows
	repeat with x from windowCount to 1 by -1
		set docName to (name of document of window x)
		set dialog_reply to display dialog docName buttons {"Keep", "Close"}
		if (button returned of dialog_reply is "Close") then
			close window x
			-- THIS checking is need
			repeat while window x exists
				delay 0.02
			end repeat
		end if
	end repeat
end tell