How to get the button clicked for an alert as sheet?


(Jonas Whale) #1

In a Xcode project, I need to display an alert as sheet with 3 buttons.
Is it possible to get the returned button with beginSheetModalForWindow:theWindow completionHandler:?

MacOS 10.11.6 (15G20015)
Script Debugger 6.0.8 (6A225)
Xcode 8.2.1 (11766.1)

(Shane Stanley) #2

You can’t use beginSheetModalForWindow:theWindow completionHandler: from AppleScript — blocks aren’t supported.

Go and download Myriad Helpers and add NSAlert+MyriadHelpers.m and NSAlert+MyriadHelpers.h to your project. Then you can use showOver:calling: something like:

set theAlert to current application's NSAlert's makeAlert:"My alert" |buttons|:{"One", "Two", "Three"} |text|:"Some explanation"
theAlert's showOver:theWindow calling:"alertDone:"

on alertDone:nameOfButtonPressed
   -- you now know the name of the button pressed

(Jonas Whale) #3

Thanks a lot Shane!

(Jonas Whale) #4

Despite all my attempts, I can’t find the way to make this work.
My script checks if a file exists already and triggers the alert if so.
The alert displays as it should, but the script doesn’t wait for the user’s response and continues as if there where not alert.

Here is how it’s organized:

script AppDelegate
	property parent : class "NSObject"
	-- IBOutlets
	-- properties
	global userButton
	on applicationWillFinishLaunching:aNotification
		-- initial statements 
	end applicationWillFinishLaunching:
	on applicationShouldTerminate:sender
		return current application's NSTerminateNow
	end applicationShouldTerminate:
	on buttonClicked:sender -- manage user click
		if sender's tag() = 1 then my mainHandler()
		if sender's tag() = 2 then quit
	end buttonClicked:
	on mainHandler()
		-- prepare the main job
		if (targetURL's checkResourceIsReachableAndReturnError:(missing value)) as boolean then
			my showAlert:"Un thème de même nom existe déjà." alertMessage:"Si vous poursuivez, le fichier sera placé dans la corbeille." alertButtons:{"Annuler", "Poursuivre"}
			log {"main", userButton}
			if userButton = "Annuler" then return
			set theFileManager to current application's NSFileManager's |defaultManager|()
			set {theResult, destURL, theError} to (theFileManager's trashItemAtURL:targetURL resultingItemURL:(reference) |error|:(reference))
			if theResult = missing value or destURL = missing value then my showAlert:"Le thème orininal n'a pu être supprimé." alertMessage:((theError's localizedDescription()) as text) alertButtons:{"Annuler"}
		end if
		-- continue the main job
	end mainHandler
	on showAlert:alertText alertMessage:alertMess alertButtons:alertButt
		set theAlert to current application's NSAlert's makeAlert:alertText buttons:alertButt |text|:alertMess
		theAlert's showOver:theWindow calling:"alertDone:"
	end showAlert:alertMessage:alertButtons:
	on alertDone:buttonPressed
		log {"alertDone", buttonPressed}
		set userButton to buttonPressed
	end alertDone:
end script


(Shane Stanley) #5

That’s how sheets behave, and you need to refactor your code accordingly. It generally means something like this in pseudo-code:

if someThingOrOther then
  my continueOn() -- rest of code
end if

on showAlert()
  -- show alert, calling alertDone:
end showAlert

on alertDone:buttonPressed
  if buttonPressed as string = "Continue" then
    my continueOn()
    -- do whatever
  end if
end alertDone:

For multiple alerts, you just keep nesting.

(Jonas Whale) #6

Ok. I missed that.
You example is clear. Thanks.