List box for ASOC Dialog Toolkit?

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:

http://piyocast.com/as/archives/5595

Okay, thanks.

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

Is there a quick fix for this? Thanks.

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