I have this handler which uses a popup to display choices to the user, but I can’t find the documentation for how to create a list box display for the window. Is there a way to do this? I’m using Shane’s Dialog Toolkit.
on showChooseList(matchList, theStr)
log “---------->Starting showChooseList.”
tell application “Adobe InDesign CC 2015”
tell docRef
copy “-- EXIT SCRIPT --” to end of matchList
try
with timeout of 30 seconds
set matchList to theLib’s sortAList:matchList
tell me to activate
set theTop to 0
set {theRule, theTop} to create rule (theTop + 12) left inset 0 rule width 200
set {colorPopup, popupLabel, theTop} to create labeled popup matchList left inset 0 bottom (theTop + 8) popup width 300 max width 500 label text “” popup left 0 initial choice “Green”
set allControls to {colorPopup, popupLabel}
set {buttonName, suppressedState, controlsResults} to display enhanced alert “Pick a link destination for:” message theStr as informational alert buttons {“OK”, “Skip”, “Cancel”} giving up after 0 acc view width 500 acc view height theTop acc view controls allControls without suppression
set userChoice to item 3 of the result
if userChoice starts with “missing value” then
set userChoice to false
else
if userChoice ends with “,” then set userChoice to text from character 1 to character -2 of userChoice
– set userChoice to theLib’s cleanTxt:(userChoice as string)
end if
end timeout
on error errMsg number errNbr
log errNbr & ": " & errMsg
log “Closing choose list window programatically.”
if errNbr = -1712 then
set userChoice to “CLOSED”
activate application id “com.adobe.InDesign”
tell application “System Events” to tell application process “Adobe InDesign CC 2015”
if exists window dialogName then
tell window dialogName
click button “Cancel”
end tell
end if
end tell
else
display dialog "Trapped error: " & errNbr & return & errMsg
end if
end try
end tell
end tell
if userChoice = false then
return false
else
return userChoice
end if
end showChooseList
What you’re calling a list box is a single-column table using NSTableView, and they actually take a bit of code to set up and manage. They’re not really within the scope of Dialog Toolkit because, apart from everything else, they need a separate object to supply their contents.
But if you want to have a go at it, this post (in Japanese) has code for creating one:
I was able to get it working (my AS skills have come a long way with Shane’s book). One question I have is how to dismiss the window after a certain period of time has elapsed. (The original code used a timeout in AS to do this.) Here’s all the new code.
I suspect the method that would need to be changed for a timeout would be this line of code: my performSelectorOnMainThread:“doModal:” withObject:(theAlert) waitUntilDone:true
P.S: I’ve added the code that is also at the top of the script:
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use script "Dialog Toolkit Plus" version "1.0"
use theLib : script "My_Handlers"
property NSAlert : a reference to current application's NSAlert
property NSIndexSet : a reference to current application's NSIndexSet
property NSScrollView : a reference to current application's NSScrollView
property NSTableView : a reference to current application's NSTableView
property NSTableColumn : a reference to current application's NSTableColumn
property NSMutableArray : a reference to current application's NSMutableArray
property NSRunningApplication : a reference to current application's NSRunningApplication
property NSAlertSecondButtonReturn : a reference to current application's NSAlertSecondButtonReturn
property theResult : 0
property returnCode : 0
property theDataSource : {}
---- Main loop excerpted. Handler is below.
on showChooseList(matchList, theStr)
log "---------->Starting showChooseList."
log matchList
activate
tell application "Adobe InDesign CC 2015"
tell docRef
-- copy "-- EXIT SCRIPT --" to end of matchList
tell me to set chooseList to theLib's sortAList:matchList
set skipSw to 0
set paramObj to {myMessage:"Pick a hyperlink text destination for:", mySubMessage:theStr, aTableList:chooseList}
set aRes to my chooseItemByTableView:paramObj
if aRes = "SKIP" then
set userChoice to false
set skipSw to 1
end if
if aRes = "CANCEL" then
set userChoice to false
set skipSw to 1
end if
if skipSw = 0 then
set userChoice to item aRes of chooseList
log "userChoice = " & userChoice
-- display dialog "Paused here"
(*
try
with timeout of 30 seconds
set matchList to theLib's sortAList:matchList
tell me to activate
set theTop to 0
set {theRule, theTop} to create rule (theTop + 12) left inset 0 rule width 200
set {colorPopup, popupLabel, theTop} to create labeled popup matchList left inset 0 bottom (theTop + 8) popup width 300 max width 500 label text "" popup left 0 initial choice "Green"
set allControls to {colorPopup, popupLabel}
set {buttonName, suppressedState, controlsResults} to display enhanced alert "Pick a link destination for:" message theStr as informational alert buttons {"OK", "Skip", "Cancel"} giving up after 0 acc view width 500 acc view height theTop acc view controls allControls without suppression
set userChoice to item 3 of the result
if userChoice starts with "missing value" then
set userChoice to false
else
if userChoice ends with "," then set userChoice to text from character 1 to character -2 of userChoice
-- set userChoice to theLib's cleanTxt:(userChoice as string)
end if
end timeout
on error errMsg number errNbr
log errNbr & ": " & errMsg
log "Closing choose list window programatically."
if errNbr = -1712 then
set userChoice to "CLOSED"
activate application id "com.adobe.InDesign"
tell application "System Events" to tell application process "Adobe InDesign CC 2015"
if exists window dialogName then
tell window dialogName
click button "Cancel"
end tell
end if
end tell
else
display dialog "Trapped error: " & errNbr & return & errMsg
end if
end try
*)
end if
end tell
end tell
if userChoice = false then
-- Space for future code.
return false
else
return userChoice
end if
end showChooseList
on chooseItemByTableView:paramObj
set aMainMes to myMessage of paramObj
set aSubMes to mySubMessage of paramObj
set aTList to (aTableList of paramObj) as list
--define the matrix size where you'll put the radio buttons
set aScrollWithTable to makeTableView(aTList, 500, 200) of me
-- set up alert
set theAlert to NSAlert's alloc()'s init()
tell theAlert
its setMessageText:aMainMes
its setInformativeText:aSubMes
its addButtonWithTitle:"OK"
its addButtonWithTitle:"Exit Script"
its addButtonWithTitle:"Skip"
its setAccessoryView:aScrollWithTable
end tell
-- show alert in modal loop
NSRunningApplication's currentApplication()'s activateWithOptions:0
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
if (my returnCode as number) = 1001 then -- user clicked "Exit Script"
error -128
end if
if (my returnCode as number) = 1002 then -- user clicked "Skip"
return "SKIP"
end if
return (aScrollWithTable's documentView's selectedRow()) + 1
end chooseItemByTableView:
on doModal:aParam
set (my returnCode) to aParam's runModal()
end doModal:
on makeTableView(aList as list, aWidth as number, aHeight as number)
set aOffset to 40
set sourceList to {}
repeat with i in aList
set the end of sourceList to {dataItem:(contents of i)}
end repeat
set theDataSource to NSMutableArray's alloc()'s init()
theDataSource's addObjectsFromArray:sourceList
set aScroll to NSScrollView's alloc()'s initWithFrame:(current application's NSMakeRect(0, aOffset, aWidth, aHeight))
set aView to NSTableView's alloc()'s initWithFrame:(current application's NSMakeRect(0, aOffset, aWidth, aHeight))
set aColumn to (NSTableColumn's alloc()'s initWithIdentifier:"dataItem")
(aColumn's setWidth:aWidth)
(aColumn's headerCell()'s setStringValue:"dataItem")
(aView's addTableColumn:aColumn)
aView's setDelegate:me
aView's setDataSource:me
aView's reloadData()
aScroll's setDocumentView:aView
aView's enclosingScrollView()'s setHasVerticalScroller:true
--Select line -1
set aIndexSet to NSIndexSet's indexSetWithIndex:0
aView's selectRowIndexes:aIndexSet byExtendingSelection:false
--Forcibly scroll to the top
--set maxHeight to aScroll's documentView()'s |bounds|()'s |size|()'s height
set aDBounds to aScroll's documentView()'s |bounds|()
if class of aDBounds = list then
--macOS 10.13 or later
set maxHeight to item 2 of item 1 of aDBounds
else
--macOS 10.10....10.12
set maxHeight to height of |size| of aDBounds
end if
set aPT to current application's NSMakePoint(0.0, -40.0) ------ (aScroll's documentView()'s |bounds|()'s |size|()'s height))
aScroll's documentView()'s scrollPoint:aPT
return aScroll
end makeTableView
--TableView Event Handlers
on numberOfRowsInTableView:aView
return my theDataSource's |count|()
end numberOfRowsInTableView:
on tableView:aView objectValueForTableColumn:aColumn row:aRow
set aRec to (my theDataSource)'s objectAtIndex:(aRow as number)
set aTitle to (aColumn's headerCell()'s title()) as string
set aRes to (aRec's valueForKey:aTitle)
return aRes
end tableView:objectValueForTableColumn:row:
You’d need to set up an NSTimer that called stopModal() or stopModalWithCode: after a certain interval. Just make sure you invalidate the timer if the user cancels the dialog beforehand, or you can end up closing the wrong dialog.
I recently upgraded to Mojave and now this portion of the script is causing an error:
on chooseItemByTableView:paramObj
set aMainMes to myMessage of paramObj
set aSubMes to mySubMessage of paramObj
set aTList to (aTableList of paramObj) as list
--define the matrix size where you'll put the radio buttons
set aScrollWithTable to makeTableView(aTList, 500, 200) of me
-- set up alert
set theAlert to NSAlert's alloc()'s init()
At this point the script is giving me an error, “NSWindow drag regions should only be invalidated on the Main Thread!” number -10000
The OS is becoming stricter in terms of what can be done on the main thread. Basically, just about everything to do with windows and views needs to be done on the main thread. So lots more performSelectorOnMainThread:.
Thanks for your help Shane. I saw this question was asked about a year ago and I used the code from your answer there.
on chooseItemByTableView:paramObj
set aMainMes to myMessage of paramObj
set aSubMes to mySubMessage of paramObj
set aTList to (aTableList of paramObj) as list
--define the matrix size where you'll put the radio buttons
set aScrollWithTable to makeTableView(aTList, 500, 200) of me
-- set up alert
my performSelectorOnMainThread:"createAlert" withObject:(missing value) waitUntilDone:true
tell theAlert
its setMessageText:aMainMes
its setInformativeText:aSubMes
its addButtonWithTitle:"OK"
its addButtonWithTitle:"Exit Script"
its addButtonWithTitle:"Skip"
its setAccessoryView:aScrollWithTable
end tell
-- show alert in modal loop
NSRunningApplication's currentApplication()'s activateWithOptions:0
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
if (my returnCode as number) = 1001 then
error -128
end if
if (my returnCode as number) = 1002 then
return "SKIP"
end if
return (aScrollWithTable's documentView's selectedRow()) + 1
end chooseItemByTableView:
on createAlert()
log "Create an alert"
set my theAlert to current application's NSAlert's alloc()'s init()
my performSelectorOnMainThread:"displayAlert:" withObject:theAlert waitUntilDone:true
tell theAlert
its setMessageText:aMainMes
its setInformativeText:aSubMes
its addButtonWithTitle:"OK"
its addButtonWithTitle:"Exit Script"
its addButtonWithTitle:"Skip"
its setAccessoryView:aScrollWithTable
end tell
log "Done"
end createAlert