I am using the following to copy a file:
on replace:sender
set allFiles to choose file with prompt "Please select your file:" with multiple selections allowed
repeat with theFile in allFiles
tell application "Finder"
set {name:fileName, name extension:nameExtension, file type:fileType} to theFile
if fileType is "png" or nameExtension is "png" then
set myPng to "~/Documents" & fileName as POSIX file
else
delay 0.2
tell current application's NSAlert's alloc's init()
its setMessageText:"Replace Photo"
its setInformativeText:"The file \"" & fileName & "\" is not a PNG file!"
its setAlertStyle:2
its setShowsSuppressionButton:false
its beginSheetModalForWindow:theWindow completionHandler:(missing value)
return
end tell
end if
if exists myPng then
delay 0.2
tell current application
display alert"There is already an older item named \""& fileName &"\" at this location." message ¬
"Do you want to replace it with the newer \"" & fileName & "\" one you're moving?" buttons {"Cancel", "Replace"} default button "Replace" as critical
set response to button returned of the result
if response is "Replace" then
delay 0.2
do shell script "rm -rf " & quoted form of POSIX path of myPng & space & "~/Documents" & myPng with administrator privileges
do shell script "mv " & quoted form of POSIX path of theFile & space & "~/Documents" with administrator privileges
end if
if response is "Cancel" then
return
end if
end tell
else
do shell script "mv " & quoted form of POSIX path of theFile & space & "~/Documents" with administrator privileges
end if
end tell
end repeat
end replace:
If there is a file with the same name in the target folder the user receives an alert, but what is happening is that with each copied file this alert is displayed, I would like to show this alert only once, just as it is done by macOS and then if the user clicks the "Replace" button all files will be replaced at once.
Your script doesn't compile so it didn't allow me to test it to really get a feel for what you're doing, so I hope I'm in the ball park with what I've come up with below.
But, aside from that, I'll be blunt: your script is a mess. You've got a Finder block that contains some AppleScriptObjC code, and then some shell function calls... I think you need to pick one, and then organise the code a bit more logically so people (especially you) can make sense of what's going on.
I typically avoid Finder for file system operations, but in this situation, it is advantageous because it allows one to compare a potential list of items (generated by a whose
filter) with a known list of items—something no other application allows (and instead thinks you wish to compare it to the number 64
). It also means that a move operation can be undone if necessary:
-- Bits of text for joining
-- Used for the alert dialogs
property lf : linefeed
property lft : linefeed & tab
property lf2 : lf & lf
property lf2t : lf2 & tab
property bullet : "›"
property li : bullet & space
-- Icon files, also used
-- for the alert dialogs
property CoreTypes : "/System/Library/CoreServices/CoreTypes.bundle"
property StopIcon : path to resource "AlertStopIcon.icns" in bundle CoreTypes
property NoteIcon : path to resource "AlertNoteIcon.icns" in bundle CoreTypes
on replace:sender
set prompt to "Please select some files:"
set fs to choose file with prompt prompt ¬
with multiple selections allowed
-- Get the directory in which the chosen files lie
set dir to (some item in fs & "::" as text)
set the text item delimiters to dir's POSIX path
-- Organise the files into two lists:
-- PNG files and non-PNG files
set PNGfs to {}
repeat with f in fs
get text items 2 thru -1 of f's POSIX path as text
set f's contents to the result
tell f to if its contents ends with ".png" then
set end of PNGfs to its contents
set its contents to null
end if
end repeat
set fs to every string in fs
set the text item delimiters to lft & li
if fs ≠ {} then display dialog ["The following files ", ¬
"are not PNG files and will be ignored:", lf2t, ¬
li & fs] as text with title ["Oops…!"] buttons ¬
["D'oh!"] with icon NoteIcon default button 1
if PNGfs = {} then return -- Nothing to move
tell application id "com.apple.Finder"
set here to dir as alias -- The source folder
set there to the (path to the documents folder) -- Destination folder
-- Enumerate files that might be replaced
set duplicates to the name of every file ¬
in there whose name is in PNGfs
if duplicates ≠ {} then tell (display dialog contents ¬
of ["The following files in ", here's POSIX path, ¬
" share names with files in ", there's POSIX path, ¬
":", lf2t & li & duplicates & lf2, "Do you want ", ¬
"to:", lft, "• Move all files anyway, replacing ", ¬
"the ones in ", there's POSIX path, ";", lft, "•", ¬
" Move only the files that can be moved without ", ¬
"replacing anything; OR", lft, "• Don't move any", ¬
" of the files for now ?"] as text ¬
with title ["Replace Existing Files?"] ¬
buttons ["Replace", "Keep", "Abort"] ¬
default button 1 with icon StopIcon) ¬
to set do to its button returned
-- If the user aborts, the script terminates.
-- If the user elects to replace existing files,
-- then we move those existing files to the trash.
-- If the user wishes to keep the existing files,
-- they remain in place. Either way, the final
-- operation is the same: move the files without
-- replacing anything.
if do = "Abort" then return 0 -- No files moved
if do = "Replace" then delete ¬
(files in there whose ¬
name is in ¬
duplicates)
move the (files in here whose ¬
name is in PNGfs) to ¬
there without replacing
end tell
end replace:
Doing it this way avoids the repeat loop and thus you only get a single dialog box per set of grouped events (one if the user selects files of the wrong type; and one if there's a risk of overwriting files).
In fact, you can even get rid of the first repeat loop that is used to split the list into two by file types: the choose file
command has a parameter called of type
, where you can specify one or more file types that the user's selection will be restricted to:
set fs to choose file with prompt prompt ¬
with multiple selections allowed ¬
of type ["png"] --OR:["public.png"]
"public.png"
is the uniform type identifier for PNG files.