Choose Folders and pass them on to another functionality

Hello experts,

maybe this question has been raised before, but I couldn´t find any specific postings. So I started this new topic, hoping you will be able to help me out of my misery.

What I am trying to do is create a little backup program for my most important folders. I want it to be flexible, so I would like to implement a choose folder dialog (only folders are involved). Here is what I have so far:



script DelOldBck
	
	on DelOldBck()
		
		set OldDefault to alias "Macintosh HD:Users:XXX:Desktop:"
		
		set OldFolders to (choose folder with prompt "Choose Folders to delete:" default location OldDefault with multiple selections allowed)
		
		tell application "Finder" to set theOLdFold to every folder of OldFolders as alias list
		
		repeat with _folder in theOLdFold
			
			delete _folder
			
		end repeat
		
	end DelOldBck
	
end script

tell DelOldBck to DelOldBck()


So basically I would like to select something which then gets passed on to another functionality, in this particular case the trash. But it might as well be a functionality to duplicate the selected folders to a different location instead of the trash. Or the bin, as you may call it…

I have done some research on POSIX, etc. and have already done some testing with different setups in this regard. Everything failed and threw an error, the above coding is the one that does not throw any errors, but doesn´t do anything either.

From what I have seen in the standard ScriptEditor, the selection is stored as an array of aliases, does that have anything to do with the problems that arise here? I am working with Catalina by the way.

Please share your knowledge on this one. If you have a solution I would also be interested why your code works. Thanks in advance!

Like this?


script DelOldBck
	
	property backupFolder : path to temporary items
	property OldDefault : path to desktop folder
	property OldFolders : {}
	
	on DelOldBck()
		set OldFolders to (choose folder with prompt "Choose Folders to delete:" default location OldDefault with multiple selections allowed)
		repeat with _folder in OldFolders -- repeat with every folder of the list OldFolders 
			tell application "Finder" to delete _folder -- tell to Finder to delete current alias (send to trash)
		end repeat
	end DelOldBck
	
	on emptyTrash()
		tell application "Finder" to empty trash
	end emptyTrash
	
	on backupFolders()
		tell application "Finder" to duplicate _folder to backupFolder replacing yes
	end backupFolders
	
end script

DelOldBck's DelOldBck()
-- DelOldBck's emptyTrash() -- uncomment to empty the trash
-- DelOldBck's backupFolders() -- uncomment to backup the folders
return {DelOldBck's backupFolder, DelOldBck's OldDefault, DelOldBck's OldFolders}

Now, replace the code after end script with this and note what happens. The script (that is, script object named “DelOldBck”) changes little the behaviour, when you change it’s properties:


set DelOldBck's OldDefault to downloads folder
DelOldBck's DelOldBck()

What a quick response, I think I understand what you are doing here.
Besides, everything you stated worked fine in my tests, thanks a lot!

There is one issue though that I couldn´t catch with for example a try statement. If in the choose folder dialog I select folders all the rest runs fine. If I don´t select anything AppleScript throws an error and quits, do you have any thoughts on how to keep the program running?

And one last question on your return remark. In my tests I could use variables defined in a particular script only in that script. So I assume that returning the variables makes them reusable again in any other script that attempts to use them? That would be a great advantage, I just did not have any time yet to test that. It would make the variables accessible on a global level.

You can do something like this:


script DelOldBck
	
	property backupFolder : path to temporary items
	property OldDefault : path to desktop folder
	property OldFolders : {}
	
	on DelOldBck()
		try
			set OldFolders to (choose folder with prompt "Choose Folders to delete:" default location OldDefault with multiple selections allowed)
			repeat with _folder in OldFolders -- repeat with every folder of the list OldFolders 
				tell application "Finder" to delete _folder -- tell to Finder to delete current alias (send to trash)
			end repeat
		on error number -128
			display notification "Errorr number -128: User cancelled. Only This call will terminated. Not the next"
		end try
	end DelOldBck
	
	on emptyTrash()
		tell application "Finder" to empty trash
	end emptyTrash
	
	on backupFolders()
		tell application "Finder" to duplicate _folder to backupFolder replacing yes
	end backupFolders
	
end script

DelOldBck's DelOldBck() -- Cancelled
DelOldBck's emptyTrash() -- Executed

You can get value of variable Var1 of script A into variable passedValue of script B. To be this available Var1 should be declared as property of script A.


script A
	property Var1 : "I am special variable of script A"
end script

script B
	on passVariable()
		set passedValue to A's Var1
	end passVariable
end script

return B's passVariable()

You can return passVariable not using B’s method (as in the previous example), but using B’s property as well:


script A
	property Var1 : "I am special variable of script 1"
end script

script B
	property passedValue : A's Var1
end script

return B's passedValue

Sorry for the delay. I had to do a little research on passing values between subroutines and during runtime. Now I think I got the hang of it :cool: So that should be clear.

I did some other stuff and then came back to testing the Choose dialog functionality again, if you still remember. Your solution to catching the error number is great, but it means that the standard Cancel button would no longer work the way it is intended to.

So I would rather leave it as it is: Clicking Cancel should mean quit and not continue. I was not able to catch any error number when clicking Choose without selecting anything, so I could not use your method in that way.

But I would want it to be like that - clicking the standard Choose button without selecting anything should mean continue anyway and not raise an error by default. A third button would of course be an option as well, so Cancel and Choose could remain standard buttons and unchanged. But I was not able to create a third button in this standard dialog, I do not think that this would be possible.

What I did notice while testing was that maybe something does get passed on as a value anyway if no selection was made and before the error is issued. So I tried to program around that and surprisingly enough the standard error did not show up anymore. It was replaced by my dialog that way. Unfortunately, if something does get selected it does not get recognised by my test coding either. But it may lead to an alternative way, any suggestions on that?



property OldDefault : path to desktop as alias

property OldFolders : {}

-- Calling Subroutines

DelOldBck(OldDefault)

EmptyTrash()

-- Subroutines

on DelOldBck(OldDefault)
	
	set OldFolders to (choose folder with prompt "Choose Folders to delete:" default location OldDefault with multiple selections allowed)
	
	set OldFoldCount to count of items of OldFolders
	
	if (OldFoldCount > 1) then
		
		repeat with _folder in OldFolders
			
			tell application "Finder" to delete _folder
			
		end repeat
		
	else
		
		display dialog "No folders in selection!"
		
	end if
	
end DelOldBck


on EmptyTrash()
	
	tell application "Finder"
		
		open the trash
		
		set TrashCount to count of items of the trash
		
		if (TrashCount > 0) then
			
			display dialog "Empty the trash?" buttons {"Cancel", "OK"} with icon caution
			
			empty the trash
			
		else
			
			display dialog "The trash is empty!" buttons {"Cancel", "OK"} default button 2 with icon caution
			
		end if
		
		delay 3
		
	end tell
	
end EmptyTrash


I edited four instructions.

if (OldFoldCount > 0) then -- EDITED, was erroneously >1 

display dialog "No folders in selection!" buttons {"OK"} default button 1 -- no need for the 2 buttons given by default

display dialog "Empty the trash?" buttons {"Cancel", "OK"}  default button 2 cancel button 1 with icon caution -- EDITED mainly for cancel button

display dialog "The trash is empty!" buttons {"OK"} default button  1 with icon caution -- no need for the 2 buttons given by default

Yesterdays, in the thread https://macscripter.net/viewtopic.php?id=47535 I described in details why I added “cancel button 1”.

HAPPILY, all users aren’t using English and it’s (quite) only on machines using this language that a button named “Cancel” issue an error number -128 when it’s triggered.
With your original code, clicking “Cancel” or clicking “OK” gave the same behavior, on my French system, the trash was emptied.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) samedi 4 avril 2020 21:12:33

One important conclusion follows from Yvan Koenig’s observations: it is better to always indicate the Cancel button explicitly. For universality of raising error -128.

Some times ago I used an other scheme.
I grabbed the localized string for Cancel and used it in the dialogs.
This way, inserting the instruction cancel button xy wasn’t required.
It worked but the result was sometimes an awful mess.
When the script displayed all its own messages in English, having a single French word in the dialogs was at least ridiculous.
So I dropped this way and switched to the cancel button xy road which, all in all, is easier to apply.

Having localized tools is fine but a bit of consistency in their GUI is good too.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) dimanche 5 avril 2020 10:35:54

Hey people, I see you started a discussion about adding Cancel buttons explicitly… This may be important in views of localisation, etc. - in my case I do not think it is. This is for private use only, and there will be no major adaptions to this localised version of mac os. Anyways, for other people it may be important.

Still, you focused too much on the empty trash part in my opinion. My question was about the choose folder dialog process, the empty trash part was just so that something useful might happen in the coding example.

Speaking of explicitly, that is why I had done this part:


if (OldFoldCount > 1) then

That is because doing it like this:


if (OldFoldCount > 0) then

will create the error that I am trying to avoid. With Count > 1 it works sort of, but not really when you select anything. Any thoughts on that? I also believe you will agree that placing a third custom button in this standard dialog will not be possible.

When you write “when you select anything”, I guess that you mean : “when you click cancel or press Escape”

In such case, given the fact that your display dialog instruction doesn’t specify the buttons, the system use its own default pair which is
OK with its shortcut return
Cancel with its shortcut Escape.
Logically, when you click Cancel you get the designed error number -128.

Try to use :

-- property OldDefault : path to desktop as alias --no need for a property

-- property OldFolders : {} -- Useless

-- Calling Subroutines
set OldDefault to path to desktop -- is ALREADY an alias !! --as alias
set maybe to my DelOldBck(OldDefault)
-- return true is you clicked OK or pressed Return after selecting at leas a folder
-- return false if you clicked Cancel or pressed Escape

if maybe then my EmptyTrash()

-- Subroutines

on DelOldBck(OldDefault)
	try
		set OldFolders to choose folder with prompt "Choose Folders to delete:" default location OldDefault with multiple selections allowed
		-- you will be here if you click OK after selecting one or several folder(s)
		set OldFoldCount to count of items of OldFolders
		-- No need for a test upon OldFoldCount which will be ≥1
		repeat with _folder in OldFolders
			
			tell application "Finder" to delete _folder
			
		end repeat
		return true
	on error errMsg number errNbr
		-- you will be here if you click Cancel after selecting nothing
		try -- try/end try, in case you remove the setting of your own set of button
			display dialog "No folders in selection!" & linefeed & errMsg & linefeed & "number #" & errNbr buttons {"OK"} default button 1
		end try
		return false
	end try
end DelOldBck


on EmptyTrash()
	
	tell application "Finder"
		
		open the trash
		
		set TrashCount to count of items of the trash
		
		if TrashCount > 0 then
			try
				display dialog "Empty the trash?" with icon caution
				-- you will be here if you click OK  or pressed Return
				empty the trash
			on error
				-- you will be here if you click Cancel  or pressed Cancel
			end try
			
		else
			
			display dialog "The trash is empty!" buttons {"OK"} default button 1 with icon caution
			
		end if
		
		delay 3
		
	end tell
	
end EmptyTrash

Oops, I forgot your late question.

set altButton to "alternate"
set cancelButton to "Cancel"
set OKbutton to "OK"
try
	set myChoice to button returned of (display dialog "Make your choice" buttons {altButton, cancelButton, OKbutton} default button OKbutton cancel button cancelButton)
on error
	-- Here if you click Cancel which will issue error number -128
	return
end try
if myChoice is OKbutton then
	-- do some task, for instance :
	error "I clicked the button " & OKbutton
else -- Here if you clicked alternateButton
	-- do alternate task, for instance :
	error "I clicked the button " & altButton
end if

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) dimanche 5 avril 2020 14:49:02

Hello again, thank you very much for looking into the matter so thoroughly.

We are getting close… I have noticed and understood what you are doing with the dialog and three buttons involved. Still, this is not the right type of dialog, but the right way of displaying buttons. I was asking if the standard choose folder dialog could display more than the standard buttons in the way your dialog does. Anyway, this problem is solved for me, I just assume that this is not possible to merge.

Regarding the Choose folder dialog, this is the code that works for me:



set OldDefault to path to desktop

set maybe to my DelOldBck(OldDefault)

if maybe then my EmptyTrash()

-- Subroutines

on DelOldBck(OldDefault)
	
	try
		
		set OldFolders to choose folder with prompt "Choose Folders to delete:" default location OldDefault with multiple selections allowed
		
		set OldFoldCount to count of items of OldFolders
		
		repeat with _folder in OldFolders
			
			tell application "Finder" to delete _folder
			
		end repeat
		
		return true
		
	on error errMsg number errNbr
		
		try
			
			-- display dialog "No folders in selection!" & linefeed & errMsg & linefeed & "number #" & errNbr buttons {"OK"} default button 1 -- Too much information ;-)
			
			display dialog "No folders in selection!" buttons {"OK"} default button 1
			
		end try
		
		return true — This change means dialog and further processing
		
	end try
	
end DelOldBck


on EmptyTrash()
	
	tell application "Finder"
		
		open the trash
		
		set TrashCount to count of items of the trash
		
		if TrashCount > 0 then
			
			try
				
				display dialog "Empty the trash?" with icon caution
				
				empty the trash
				
			on error
				
			end try
			
		else
			
			display dialog "The trash is empty!" buttons {"OK"} default button 1 with icon caution
			
		end if
		
		delay 3
		
	end tell
	
end EmptyTrash


I have made only one relevant change to your coding, and that was setting the return to true when getting the error of clicking Cancel when not choosing anything in the first dialog. That means that a dialog is displayed and the program will resume, no matter what. In the next dialog you still have the chance to escape it all again or continue to empty the trash. I sometimes start this program and delete items, only to quit the program afterwards, do something else and start it all over again, and then there is nothing to delete anymore, that is what this part is for actually. Just a means of having the program continue, when nothing gets selected.

Funny enough, when you click Choose you still get the error that I was not able to catch. After displaying the error, AppleScript keeps running in the background and after a while continues by itself and enters the empty trash part. This would help and must be some kind of feature, not bad, but the delay until the program resumes automatically is just too long, so this is not an alternative.

Instead, your way of catching the error and continue earlier is the way to go for me. So this topic is solved and closed as far as I am concerned.

Thanks again for your reliable expertise everyone, much appreciated.