NSAlert/ASObj-C question

Shane,

I have a question for the script below. I was testing out the “call help button” operation for the alert. When I wondered why I couldn’t just put NSAlert’s “runModal” in for the selector in “performSelectorOnMainThread …” at the end of the script. I tried both “runModal” and “NSAlert’s runModal” and neither worked. It worked when I gave a handler name as the parameter. You’ve alway done the “performSelectorOnMain …” then “runModal” after that. Are these 2 methods the equivalent? Why couldn’t I use “runModal” for the selector parameter? It seems odd it worked using an AppleScript handler but it didn’t work using an Objective C method name.

Just out of curiosity is it safe to use the script object “DisplaySpecialHelp” to implement the “help” function test. The documentation talked about an object that had a routine which could handle the alertShowHelp function and I thought of a script object. But now that I think about it the seems like a weird. But it has worked with what little testing I’ve done with it.

Bill

use AppleScript version "2.3.1"
use scripting additions
use framework "AppKit"

script DisplaySpecialHelp
	on alertShowHelp:alert
		display dialog "This is the special help." buttons {"OK"} default button "OK"
		return true
	end alertShowHelp:
end script

on DisplayAppModalDialog:theAlert
	theAlert's runModal()
end DisplayAppModalDialog:

set theAlert to current application's NSAlert's alloc()'s init()

set showsHelp of theAlert to true
set delegate of theAlert to DisplaySpecialHelp

tell theAlert
	its setAlertStyle:1
	its setMessageText:"This is a test."
	its (|window|()'s setAutorecalculatesKeyViewLoop:true)
end tell

my performSelectorOnMainThread:"DisplayAppModalDialog:" withObject:theAlert waitUntilDone:true

It has to be put in a handler so a property can be set to the result of runModal, because that’s the only way you can find out what button was pressed. It should work, as in show the alert, if you use it as the selector directly, but it won’t be of any use.

If the script object works, it works. You could also just use me as the delegate, and put the handler in the main script.

Something like this?
[edit:]
I just want to understand Bill’s question.
I mean, is the question “why a script like the one below does not return the clicked button of the main alert?”
[/edit]

-- show the main alert
set mainAlert to current application's NSAlert's alloc's init()
tell mainAlert
	its setDelegate:me
	its setShowsHelp:true
	its setMessageText:"Main alert message."
	its setInformativeText:"Main alert informative text."
	its setAlertStyle:0
	its addButtonWithTitle:"OK"
	my performSelectorOnMainThread:(its runModal()) withObject:mainAlert waitUntilDone:true
end tell


-- show the help alert
on alertShowHelp:mainAlert
	set helpAlert to current application's NSAlert's alloc's init()
	tell helpAlert
		its setMessageText:"Help alert message."
		its setInformativeText:"Help alert informative text."
		my performSelectorOnMainThread:(its runModal()) withObject:helpAlert waitUntilDone:true
	end tell
	return true
end alertShowHelp:

If I understand well Shane’s suggestion, the script should be:

use AppleScript version "2.4"
use scripting additions
use framework "AppKit"

property returnCode : missing value

-- show the main alert
set mainAlert to current application's NSAlert's alloc's init()
tell mainAlert
	its setDelegate:me
	its setShowsHelp:true
	its setMessageText:"Main alert message."
	its setInformativeText:"Main alert informative text."
	its setAlertStyle:0
	its addButtonWithTitle:"OK"
	its addButtonWithTitle:"Cancel"
end tell
my performSelectorOnMainThread:"showTheAlert:" withObject:mainAlert waitUntilDone:true

returnCode


-- show the help alert
on alertShowHelp:mainAlert
	set helpAlert to current application's NSAlert's alloc's init()
	tell helpAlert
		its setMessageText:"Help alert message."
		its setInformativeText:"Help alert informative text."
		my performSelectorOnMainThread:"showTheAlert:" withObject:helpAlert waitUntilDone:true
	end tell
	return true
end alertShowHelp:

-- check we are running in foreground
on showTheAlert:theAlert
	if not (current application's NSThread's isMainThread()) as boolean then error "This handler must be called on the main thread." from current application
	set my returnCode to theAlert's runModal()
end showTheAlert:

Is the performSelectorOnMainThread method absolutely necessary for the help alert or can we safely use runModal here?

(I wonder why these scripts didn’t format as appleScripts. Maybe they needed more spaces at the start?)

(Also I’m noticing that the “Open in Script Debugger” link in Bill’s script doesn’t work. I’ve quit and relaunched SD and Safari, and it seems to have no effect. The link seems active, the cursor changes to the pointer and the link changes color when I hover, but it seems to have no effect. Other “Open in Script Debugger” links in the forum are still working.)

Anything that results in screen drawing should generally be done on the main thread. If you’re not sure, have Console open as you run the relevant code – you’ll see warnings (or a crash) if you’re doing the wrong thing.

They should be working now.

1 Like

Yes, the are working now! Thanks!

What is a “Open in Script Debugger” link? Is there something special I should do to make a script open in SD?

Bill

At the top of the script you posted in this thread the forum added a link that reads “Open in Script Debugger” Click on it and your script opens in a new, uncompiled SD window/tab.

I’m not sure by what magic the system recognizes it’s a script, but I think putting four spaces at the start works. (That’s probably documented somewhere)

You can indent by 4 spaces/1 tab or you can place three back-ticks before the first statement and after the last:

```
set a to 100
```

By default, forum.latenightsw.com assumes all code is AppleScript code, but you can indicate the language if you want:

```applescript
set a to 100
```

…or…

```ruby
a = 100
b = "Hello World"
```

Formatting is otherwise Markdown.

1 Like