I’m using Dialog Toolkit 1.0.3 by Shane Stanley. But I’m writing in Script Debugger 6, which is problematic because the Dialog Toolkit commands need to be run on the main thread, which Script Debugger 6 doesn’t seem to support yet.
So I’m trying to adapt the approach in Chapter 26 of Everyday AppleScriptObjC for ensuring that Dialog Toolkit’s handler that creates the NSAlert is always run on the main thread.
For this, I’m kind of bumbling around in the dark, as ASObjC is pretty new to me. I’ll paste the handler twice below, first prior to my edit and then with the edit suggested in Everyday AppleScriptObjC. My question is whether my modification will permanently remove the need for me to be concerned about using this library on the main thread, or if I need to find a different approach.
The modification is after the tell block for theAlert. I’ve just added its performSelectorOnMainThread:"displayAlert:" withObject:theAlert waitUntilDone:true within the handler. I’m asking because I don’t quite understand yet what this is doing, just following the book’s instructions.
Original handler in Dialog Toolkit 1.0.3:
on displayAlert:mainText message:theExplanation asStyle:styleNum buttons:buttonsList suppression:showSuppression givingUpAfter:giveUp AVWidth:theWidth AVHeight:theHeight AVControls:controlsList -- check we have the OK set theResult to (current application's AEInteractWithUser(-1, missing value, missing value)) as integer if theResult is not 0 then error "Unable to show dialog (AEInteractWithUser() failed)." -- make the accessory view set theAccessoryView to current application's NSView's alloc()'s initWithFrame:(current application's NSMakeRect(0, 0, theWidth, theHeight)) theAccessoryView's setSubviews:controlsList -- reverse buttons because they get added in reverse order cf AS set buttonsList to reverse of buttonsList -- create an alert set theAlert to current application's NSAlert's alloc()'s init() -- set up alert tell theAlert its setAlertStyle:styleNum its setMessageText:mainText its setInformativeText:theExplanation repeat with anEntry in buttonsList (its addButtonWithTitle:anEntry) end repeat its setShowsSuppressionButton:showSuppression its setAccessoryView:theAccessoryView its (|window|()'s setAutorecalculatesKeyViewLoop:true) end tell -- if giveUp value > 0, tell the app to abort any modal event loop after that time, and thus close the panel if giveUp > 0 then current application's NSApp's performSelector:"abortModal" withObject:(missing value) afterDelay:giveUp inModes:{current application's NSModalPanelRunLoopMode} -- show alert in modal loop set returnCode to theAlert's runModal() -- if a giveUp time was specified and the alert didn't timeout, cancel the pending abort request if giveUp > 0 and returnCode is not current application's NSModalResponseAbort then current application's NSObject's cancelPreviousPerformRequestsWithTarget:(current application's NSApp) selector:"abortModal" object:(missing value) -- get values after alert is closed set suppressedState to theAlert's suppressionButton()'s state() as boolean set buttonNumber to returnCode mod 1000 + 1 -- where 1 = right-most button if buttonNumber = 0 then set buttonName to "Gave Up" else set buttonName to item buttonNumber of buttonsList end if -- get values from controls set controlResults to {} repeat with aControl in controlsList if (aControl's isKindOfClass:(current application's NSTextField)) as boolean then set end of controlResults to aControl's stringValue() as text else if (aControl's isKindOfClass:(current application's NSPopUpButton)) as boolean then set end of controlResults to aControl's titleOfSelectedItem() as text else if (aControl's isKindOfClass:(current application's NSButton)) as boolean then set end of controlResults to aControl's state() as boolean else if (aControl's isKindOfClass:(current application's NSPathControl)) as boolean then set end of controlResults to aControl's |URL|()'s |path|() as text else if (aControl's isKindOfClass:(current application's NSMatrix)) as boolean then set end of controlResults to aControl's selectedCell()'s title() as text else -- NSBox set end of controlResults to missing value end if end repeat return {buttonName, suppressedState, controlResults} end displayAlert:message:asStyle:buttons:suppression:givingUpAfter:AVWidth:AVHeight:AVControls:
and as modified:
on displayAlert:mainText message:theExplanation asStyle:styleNum buttons:buttonsList suppression:showSuppression givingUpAfter:giveUp AVWidth:theWidth AVHeight:theHeight AVControls:controlsList -- check we have the OK set theResult to (current application's AEInteractWithUser(-1, missing value, missing value)) as integer if theResult is not 0 then error "Unable to show dialog (AEInteractWithUser() failed)." -- make the accessory view set theAccessoryView to current application's NSView's alloc()'s initWithFrame:(current application's NSMakeRect(0, 0, theWidth, theHeight)) theAccessoryView's setSubviews:controlsList -- reverse buttons because they get added in reverse order cf AS set buttonsList to reverse of buttonsList -- create an alert set theAlert to current application's NSAlert's alloc()'s init() -- set up alert tell theAlert its setAlertStyle:styleNum its setMessageText:mainText its setInformativeText:theExplanation repeat with anEntry in buttonsList (its addButtonWithTitle:anEntry) end repeat its setShowsSuppressionButton:showSuppression its setAccessoryView:theAccessoryView its (|window|()'s setAutorecalculatesKeyViewLoop:true) end tell its performSelectorOnMainThread:"displayAlert:" withObject:theAlert waitUntilDone:true -- if giveUp value > 0, tell the app to abort any modal event loop after that time, and thus close the panel if giveUp > 0 then current application's NSApp's performSelector:"abortModal" withObject:(missing value) afterDelay:giveUp inModes:{current application's NSModalPanelRunLoopMode} -- show alert in modal loop set returnCode to theAlert's runModal() -- if a giveUp time was specified and the alert didn't timeout, cancel the pending abort request if giveUp > 0 and returnCode is not current application's NSModalResponseAbort then current application's NSObject's cancelPreviousPerformRequestsWithTarget:(current application's NSApp) selector:"abortModal" object:(missing value) -- get values after alert is closed set suppressedState to theAlert's suppressionButton()'s state() as boolean set buttonNumber to returnCode mod 1000 + 1 -- where 1 = right-most button if buttonNumber = 0 then set buttonName to "Gave Up" else set buttonName to item buttonNumber of buttonsList end if -- get values from controls set controlResults to {} repeat with aControl in controlsList if (aControl's isKindOfClass:(current application's NSTextField)) as boolean then set end of controlResults to aControl's stringValue() as text else if (aControl's isKindOfClass:(current application's NSPopUpButton)) as boolean then set end of controlResults to aControl's titleOfSelectedItem() as text else if (aControl's isKindOfClass:(current application's NSButton)) as boolean then set end of controlResults to aControl's state() as boolean else if (aControl's isKindOfClass:(current application's NSPathControl)) as boolean then set end of controlResults to aControl's |URL|()'s |path|() as text else if (aControl's isKindOfClass:(current application's NSMatrix)) as boolean then set end of controlResults to aControl's selectedCell()'s title() as text else -- NSBox set end of controlResults to missing value end if end repeat return {buttonName, suppressedState, controlResults} end displayAlert:message:asStyle:buttons:suppression:givingUpAfter:AVWidth:AVHeight:AVControls:
— Jacob M. Small, PrincipalJ. Madison PLC1750 Tysons Boulevard, Suite 1500McLean, Virginia 22102T 703.910.5062 F 703.910.5107 www.jmadisonplc.com
|