Myriad Tables Questions

No — it’s both or nothing.

I’m all set, then. But is there an NSView I could use to add a text box?

Sure — look in Dialog Toolkit Plus for the createFieldMainThread: and createLabelMainThread: handlers.

Also, if you’re not using checkboxClicked:, just cut it out, plus the two checkbox calls setTarget: and setAction:.

I may be in over my head with this, but I can’t make it work. What am I doing wrong?

use framework "Carbon" -- AEInteractWithUser() is in Carbon 
use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
use script "Myriad Tables Lib" version "1.0.7"
use scripting additions
property NSTextField : a reference to current application's NSTextField
property NSLeftTextAlignment : a reference to 0
property NSNoTitle : a reference to 0
property NSRegularControlSize : a reference to 0
property NSCenterTextAlignment : a reference to 2
property NSPathStylePopUp : a reference to 2
property NSRightTextAlignment : a reference to 1

property defaultRows : {1, 2}
property checkState : 1
property theCheckbox : missing value
property thePopup : missing value
property theAccessoryView : missing value
property emailList : {{}}


set popupList to {}
set myDate to (current date)
repeat with x from 1 to 5
   set myDate to myDate + 1 * days
   set the end of popupList to date string of myDate
end repeat
set defaultDate to item 1 of popupList
set tablePrompt to "Select the date, email addresses and indicate if there are ads on the page"
set selectedRows to {1, 2}

set {enteredText, placeHolder, theLeft, theBottom, theWidth, extraHeight, acceptsTabs} to ¬
   {"Label Entry Text", "Placeholder Text", 10, 10, 17, 10, true}
set {labelString, theLeft, theBottom, maxWidth, alignment, wrapsBool, controlSize, boldType} to ¬
   {"labelString", 0, 0, 50, "right", true, 12, true}
repeat
   if current application's NSThread's isMainThread() as boolean then
      my createCheckBoxMainThread:{"Page has other editorial", "checkboxClicked:", checkState}
      my createPopupMainThread:{popupList, defaultDate}
      my buildAccessoryViewMainThread:{theCheckbox, thePopup}
      --my createFieldMainThread:{enteredText, placeHolder, theLeft, theBottom, theWidth, extraHeight, acceptsTabs}
      
      my createLabelMainThread:{labelString, theLeft, theBottom, maxWidth, alignment, wrapsBool, controlSize, boldType}
   else
      my performSelectorOnMainThread:"createCheckBoxMainThread:" withObject:{"Page has other editorial", "checkboxClicked:", checkState} waitUntilDone:true
      my performSelectorOnMainThread:"createPopupMainThread:" withObject:{popupList, defaultDate} waitUntilDone:true
      my performSelectorOnMainThread:"buildAccessoryViewMainThread:" withObject:{theCheckbox, thePopup} waitUntilDone:true
      my performSelectorOnMainThread:"createLabelMainThread:" withObject:{labelString, theLeft, theBottom, maxWidth, alignment, wrapsBool, controlSize, boldType} waitUntilDone:true
      my performSelectorOnMainThread:"createFieldMainThread:" withObject:{enteredText, placeHolder, theLeft, theBottom, theWidth, extraHeight, acceptsTabs} waitUntilDone:true
      
   end if
   
   set theTable to make new table with data emailList ¬
      with title ¬
      "TV Highlights and grid pages" with prompt tablePrompt ¬
      multiple selections allowed true ¬
      can add and delete true ¬
      editable columns {1, 2} ¬
      column headings {"Label", "Address"} ¬
      row numbering false ¬
      initially selected rows selectedRows ¬
      without empty selection allowed
   
   modify table theTable ¬
      OK button name ¬
      "Okay" cancel button name ¬
      "Cancel" extra button name ¬
      "Refresh" highlighted rows {} ¬
      alternate backgrounds false ¬
      row dragging false ¬
      without column reordering
   modify table theTable accessory view theAccessoryView
   
   set theAccessoryView to missing value -- to avoid error messages when saving
   
   set tableResult to display table theTable ¬
      with extended results
   
   set selectedRows to rows selected of tableResult
   set buttonClicked to button number of tableResult
   set emailAddresses to values selected of tableResult
   log emailAddresses
   set finalPosition to final position of tableResult
   set fullList to values returned of tableResult
   
   set otherEdOnPage to theCheckbox's state() as boolean
   if otherEdOnPage then
      set checkState to 1
   else
      set checkState to 0
   end if
   set theCheckbox to missing value -- to avoid error messages when saving
   set pubDate to thePopup's title() as text
   set thePopup to missing value
   
   if buttonClicked is 1 then --OK
      set confirmationPrompt to {"Please confirm notification:", ""}
      set displayAddresses to my stripNamesFromAddresses(emailAddresses)
      set AppleScript's text item delimiters to {", "}
      set displayAddresses to displayAddresses as text
      set the end of confirmationPrompt to "Send to: " & displayAddresses
      set confirmationtext to {"The TV grid and highlights page for " & pubDate & " is ready for print. ", ""}
      if otherEdOnPage then
         set the end of confirmationtext to "The page has other editorial so I won't release."
      else
         set the end of confirmationtext to "I can release when OK'd."
      end if
      set AppleScript's text item delimiters to {return}
      
      set userResponse to display dialog confirmationPrompt as text ¬
         default answer confirmationtext as text ¬
         buttons {"Cancel", "Refresh", "Confirm"} ¬
         default button 3 ¬
         with title ¬
         "Email Confirmation" giving up after 60
      if the button returned of userResponse is "Confirm" then
         set emailText to text returned of userResponse
         exit repeat
      else
         if the button returned of userResponse is "Refresh" then
            set confirmationtext to {"The TV grid and highlights page for " & pubDate & " is ready for print. ", ""}
            if otherEdOnPage then
               set the end of confirmationtext to "The page has other editorial so I won't release."
            else
               set the end of confirmationtext to "I can release when OK'd."
            end if
            
            set tablePrompt to (confirmationPrompt as text) & return & return & confirmationtext as text
         end if
      end if
   else if buttonClicked is 3 then
      return
      
   end if
end repeat

on stripNamesFromAddresses(emailAddresses)
   log emailAddresses
   set newAddressList to {}
   set saveTID to AppleScript's text item delimiters
   set AppleScript's text item delimiters to {": "}
   repeat with thisAddress in emailAddresses
      set the end of newAddressList to item 2 of thisAddress as text
      log newAddressList
   end repeat
   
   set AppleScript's text item delimiters to saveTID
   return newAddressList
end stripNamesFromAddresses

on createCheckBoxMainThread:theArg
   set {theTitle, theAction, theDefault} to theArg as list
   -- build a checkbox
   set my theCheckbox to current application's NSButton's alloc()'s initWithFrame:{{10, 10}, {320, 20}}
   tell theCheckbox
      its setButtonType:(current application's NSSwitchButton)
      its setTitle:theTitle
      its setTarget:me
      --   its setAction:theAction -- a handler in this script
      its setState:theDefault
   end tell
end createCheckBoxMainThread:

on createPopupMainThread:theArg
   set {entryList, defaultValue} to theArg as list
   set my thePopup to current application's NSPopUpButton's alloc()'s initWithFrame:{{10, 30}, {300, 35}} pullsDown:false
   thePopup's addItemsWithTitles:entryList
   thePopup's selectItemWithTitle:defaultValue
end createPopupMainThread:

on buildAccessoryViewMainThread:theControls
   set my theAccessoryView to current application's NSView's alloc()'s initWithFrame:{{0, 0}, {320, 60}}
   repeat with aControl in theControls
      (theAccessoryView's addSubview:aControl)
   end repeat
end buildAccessoryViewMainThread:
on createFieldMainThread:theArg
   set {placeHolder, theLeft, theBottom, theWidth, extraHeight, acceptsTabs} to theArg as list
   set theTop to theBottom + 22 + extraHeight
   set theField to (NSTextField's alloc()'s initWithFrame:{{theLeft, theBottom}, {theWidth, theTop - theBottom}})
   tell theField
      (its setEditable:true)
      (its setBezeled:true)
      its (cell()'s setPlaceholderString:placeHolder)
      if extraHeight > 0 then its (cell()'s setWraps:true)
      its setStringValue:enteredText
      if acceptsTabs then its setDelegate:me
   end tell
   -- return theField, the top of the field
   set my handlerResult to {theField, theTop}
end createFieldMainThread:


on createLabelMainThread:theArg
   set {labelString, theLeft, theBottom, maxWidth, alignment, wrapsBool, controlSize, boldType} to theArg as list
   -- create label, set size and make font
   set theLabel to (NSTextField's alloc()'s initWithFrame:{{theLeft, theBottom}, {maxWidth, 17}})
   set theFont to my fontOfControlSize:controlSize boldType:boldType
   -- format label
   if alignment begins with "r" then
      theLabel's setAlignment:NSRightTextAlignment
   else if alignment begins with "c" then
      theLabel's setAlignment:NSCenterTextAlignment
   else
      theLabel's setAlignment:NSLeftTextAlignment
   end if
   tell theLabel
      its setFont:theFont
      its setPreferredMaxLayoutWidth:maxWidth
      (its setStringValue:labelString)
      (its setEditable:false)
      (its setSelectable:true)
      (its setBordered:false)
      (its setDrawsBackground:false)
      its (cell()'s setWraps:wrapsBool)
   end tell
   -- size label
   theLabel's setFrameSize:(theLabel's fittingSize())
   -- set alignment
   set theFrame to theLabel's frame()
   if class of theFrame is record then
      set {width:newWidth, height:theHeight} to theFrame's |size|
   else
      set {newWidth, theHeight} to item 2 of theFrame
   end if
   if alignment begins with "r" then
      set theOrigin to {theLeft + maxWidth - newWidth, theBottom}
   else if alignment begins with "c" then
      set theOrigin to {(theLeft + (maxWidth - newWidth) / 2), theBottom}
   else
      set theOrigin to {theLeft, theBottom}
   end if
   theLabel's setFrameOrigin:theOrigin
   -- return theLabel, the top of the label, and its width
   set my handlerResult to {theLabel, theBottom + theHeight, newWidth}
end createLabelMainThread:
 

The geometry is all askew, but this should give you something to work from:

use framework "Carbon" -- AEInteractWithUser() is in Carbon 
use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
use script "Myriad Tables Lib" version "1.0.7"
use scripting additions
property NSTextField : a reference to current application's NSTextField
property NSLeftTextAlignment : a reference to 0
property NSNoTitle : a reference to 0
property NSRegularControlSize : a reference to 0
property NSCenterTextAlignment : a reference to 2
property NSPathStylePopUp : a reference to 2
property NSRightTextAlignment : a reference to 1

property defaultRows : {1, 2}
property checkState : 1
property theCheckbox : missing value
property thePopup : missing value
property handlerResult : missing value
property theAccessoryView : missing value
property emailList : {{}}

set popupList to {}
set myDate to (current date)
repeat with x from 1 to 5
	set myDate to myDate + 1 * days
	set the end of popupList to date string of myDate
end repeat
set defaultDate to item 1 of popupList
set tablePrompt to "Select the date, email addresses and indicate if there are ads on the page"
set selectedRows to {1, 2}

set {enteredText, placeHolder, theLeft, theBottom, theWidth, extraHeight, acceptsTabs} to ¬
	{"Label Entry Text", "Placeholder Text", 10, 10, 17, 10, true}
set {labelString, theLeft, theBottom, maxWidth, alignment, wrapsBool, controlSize, boldType} to ¬
	{"labelString", 0, 0, 50, "right", true, 12, true}
repeat
	if current application's NSThread's isMainThread() as boolean then
		my createCheckBoxMainThread:{"Page has other editorial", "checkboxClicked:", checkState}
		my createPopupMainThread:{popupList, defaultDate}
		my createFieldMainThread:{enteredText, placeHolder, theLeft, theBottom, theWidth, extraHeight, acceptsTabs}
		set {theField, theBottom} to handlerResult
		my createLabelMainThread:{labelString, theLeft, theBottom, maxWidth, alignment, wrapsBool, controlSize, boldType}
		set {theLabel, theBottom, newWidth} to handlerResult
		my buildAccessoryViewMainThread:{theLabel, theField, theCheckbox, thePopup}
	else
		my performSelectorOnMainThread:"createCheckBoxMainThread:" withObject:{"Page has other editorial", "checkboxClicked:", checkState} waitUntilDone:true
		my performSelectorOnMainThread:"createPopupMainThread:" withObject:{popupList, defaultDate} waitUntilDone:true
		my performSelectorOnMainThread:"createFieldMainThread:" withObject:{enteredText, placeHolder, theLeft, theBottom, theWidth, extraHeight, acceptsTabs} waitUntilDone:true
		set {theField, theBottom} to handlerResult
		my performSelectorOnMainThread:"createLabelMainThread:" withObject:{labelString, theLeft, theBottom, maxWidth, alignment, wrapsBool, controlSize, boldType} waitUntilDone:true
		set {theLabel, theBottom, newWidth} to handlerResult
		my performSelectorOnMainThread:"buildAccessoryViewMainThread:" withObject:{theLabel, theField, theCheckbox, thePopup} waitUntilDone:true
		
	end if
	
	set theTable to make new table with data emailList ¬
		with title ¬
		"TV Highlights and grid pages" with prompt tablePrompt ¬
		multiple selections allowed true ¬
		can add and delete true ¬
		editable columns {1, 2} ¬
		column headings {"Label", "Address"} ¬
		row numbering false ¬
		initially selected rows selectedRows ¬
		without empty selection allowed
	
	modify table theTable ¬
		OK button name ¬
		"Okay" cancel button name ¬
		"Cancel" extra button name ¬
		"Refresh" highlighted rows {} ¬
		alternate backgrounds false ¬
		row dragging false ¬
		without column reordering
	modify table theTable accessory view theAccessoryView
	
	set theAccessoryView to missing value -- to avoid error messages when saving
	
	set tableResult to display table theTable ¬
		with extended results
	
	set selectedRows to rows selected of tableResult
	set buttonClicked to button number of tableResult
	set emailAddresses to values selected of tableResult
	log emailAddresses
	set finalPosition to final position of tableResult
	set fullList to values returned of tableResult
	
	set otherEdOnPage to theCheckbox's state() as boolean
	if otherEdOnPage then
		set checkState to 1
	else
		set checkState to 0
	end if
	set theCheckbox to missing value -- to avoid error messages when saving
	set pubDate to thePopup's title() as text
	set thePopup to missing value
	
	if buttonClicked is 1 then --OK
		set confirmationPrompt to {"Please confirm notification:", ""}
		set displayAddresses to my stripNamesFromAddresses(emailAddresses)
		set AppleScript's text item delimiters to {", "}
		set displayAddresses to displayAddresses as text
		set the end of confirmationPrompt to "Send to: " & displayAddresses
		set confirmationtext to {"The TV grid and highlights page for " & pubDate & " is ready for print. ", ""}
		if otherEdOnPage then
			set the end of confirmationtext to "The page has other editorial so I won't release."
		else
			set the end of confirmationtext to "I can release when OK'd."
		end if
		set AppleScript's text item delimiters to {return}
		
		set userResponse to display dialog confirmationPrompt as text ¬
			default answer confirmationtext as text ¬
			buttons {"Cancel", "Refresh", "Confirm"} ¬
			default button 3 ¬
			with title ¬
			"Email Confirmation" giving up after 60
		if the button returned of userResponse is "Confirm" then
			set emailText to text returned of userResponse
			exit repeat
		else
			if the button returned of userResponse is "Refresh" then
				set confirmationtext to {"The TV grid and highlights page for " & pubDate & " is ready for print. ", ""}
				if otherEdOnPage then
					set the end of confirmationtext to "The page has other editorial so I won't release."
				else
					set the end of confirmationtext to "I can release when OK'd."
				end if
				
				set tablePrompt to (confirmationPrompt as text) & return & return & confirmationtext as text
			end if
		end if
	else if buttonClicked is 3 then
		return
		
	end if
end repeat

on stripNamesFromAddresses(emailAddresses)
	log emailAddresses
	set newAddressList to {}
	set saveTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to {": "}
	repeat with thisAddress in emailAddresses
		set the end of newAddressList to item 2 of thisAddress as text
		log newAddressList
	end repeat
	
	set AppleScript's text item delimiters to saveTID
	return newAddressList
end stripNamesFromAddresses

on createCheckBoxMainThread:theArg
	set {theTitle, theAction, theDefault} to theArg as list
	-- build a checkbox
	set my theCheckbox to current application's NSButton's alloc()'s initWithFrame:{{10, 10}, {320, 20}}
	tell theCheckbox
		its setButtonType:(current application's NSSwitchButton)
		its setTitle:theTitle
		its setTarget:me
		--   its setAction:theAction -- a handler in this script
		its setState:theDefault
	end tell
end createCheckBoxMainThread:

on createPopupMainThread:theArg
	set {entryList, defaultValue} to theArg as list
	set my thePopup to current application's NSPopUpButton's alloc()'s initWithFrame:{{10, 30}, {300, 35}} pullsDown:false
	thePopup's addItemsWithTitles:entryList
	thePopup's selectItemWithTitle:defaultValue
end createPopupMainThread:

on buildAccessoryViewMainThread:theControls
	set my theAccessoryView to current application's NSView's alloc()'s initWithFrame:{{0, 0}, {320, 60}}
	repeat with aControl in theControls
		(theAccessoryView's addSubview:aControl)
	end repeat
end buildAccessoryViewMainThread:
on createFieldMainThread:theArg
	set {enteredText, placeHolder, theLeft, theBottom, theWidth, extraHeight, acceptsTabs} to theArg as list
	set theTop to theBottom + 22 + extraHeight
	set theField to (NSTextField's alloc()'s initWithFrame:{{theLeft, theBottom}, {theWidth, theTop - theBottom}})
	tell theField
		(its setEditable:true)
		(its setBezeled:true)
		its (cell()'s setPlaceholderString:placeHolder)
		if extraHeight > 0 then its (cell()'s setWraps:true)
		its setStringValue:enteredText
		if acceptsTabs then its setDelegate:me
	end tell
	-- return theField, the top of the field
	set my handlerResult to {theField, theTop}
end createFieldMainThread:


on createLabelMainThread:theArg
	set {labelString, theLeft, theBottom, maxWidth, alignment, wrapsBool, controlSize, boldType} to theArg as list
	-- create label, set size and make font
	set theLabel to (NSTextField's alloc()'s initWithFrame:{{theLeft, theBottom}, {maxWidth, 17}})
	-- format label
	if alignment begins with "r" then
		theLabel's setAlignment:NSRightTextAlignment
	else if alignment begins with "c" then
		theLabel's setAlignment:NSCenterTextAlignment
	else
		theLabel's setAlignment:NSLeftTextAlignment
	end if
	tell theLabel
		its setPreferredMaxLayoutWidth:maxWidth
		(its setStringValue:labelString)
		(its setEditable:false)
		(its setSelectable:true)
		(its setBordered:false)
		(its setDrawsBackground:false)
		its (cell()'s setWraps:wrapsBool)
	end tell
	-- size label
	theLabel's setFrameSize:(theLabel's fittingSize())
	-- set alignment
	set theFrame to theLabel's frame()
	if class of theFrame is record then
		set {width:newWidth, height:theHeight} to theFrame's |size|
	else
		set {newWidth, theHeight} to item 2 of theFrame
	end if
	if alignment begins with "r" then
		set theOrigin to {theLeft + maxWidth - newWidth, theBottom}
	else if alignment begins with "c" then
		set theOrigin to {(theLeft + (maxWidth - newWidth) / 2), theBottom}
	else
		set theOrigin to {theLeft, theBottom}
	end if
	theLabel's setFrameOrigin:theOrigin
	-- return theLabel, the top of the label, and its width
	set my handlerResult to {theLabel, theBottom + theHeight, newWidth}
end createLabelMainThread:

Actually, @estockly, a better approach would be to use Display Dialog Toolkit itself to build the controls. Then you just need your own handler to build the accessory view, which you then pass on.

So here’s such a script. The first part is from Align sample.scpt, which builds a dialog of various widgets. But once the script has created the controls, instead of showing them in a DDT window, it adds them to an accessory view and passes that to some of your Myriad Tables code.

This is a lot simpler: you can build your accessory view as a DDT dialog first, and you don’t need to deal with nearly as much ASObjC code yourself. Just remember the size limit is 600 x 200:

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use script "Dialog Toolkit Plus" version "1.1.0"
use script "Myriad Tables Lib" version "1.0.9"
property theAccessoryView : missing value

-- This code is from the Dialog Toolkit Plus sample "Aligned sample.scpt"
set accViewWidth to 400
set {theButtons, minWidth} to create buttons {"Cancel", "Maybe", "It All Depends", "OK"} default button "OK" cancel button "Cancel" with equal widths
if minWidth > accViewWidth then set accViewWidth to minWidth -- make sure buttons fit
-- to make it look better, we can get the length of the longest label we will use, and use that to align the controls
set theLabelStrings to {"This job is for:", "Operator's name:"}
set maxLabelWidth to max width for labels theLabelStrings
set controlLeft to maxLabelWidth + 8
-- start from the bottom with a checkbox
set {theCheckbox, theTop, newWidth} to create checkbox "One side only" left inset controlLeft bottom 0 max width accViewWidth without initial state
-- then a labeled popup
set {colorPopup, popupLabel, theTop} to create labeled popup {"Red", "Green", "Blue"} left inset 0 bottom (theTop + 8) popup width 100 max width accViewWidth label text (item 1 of theLabelStrings) popup left controlLeft initial choice "Green"
-- then a labeled field
set {operatorField, operatorLabel, theTop, fieldLeft} to create side labeled field (short user name of (system info)) placeholder text "Your name" left inset 0 bottom (theTop + 12) total width accViewWidth label text (item 2 of theLabelStrings) field left controlLeft
-- then a small explanatory label
set {messageLabel, theTop} to create label "More text goes in here" bottom theTop + 12 max width accViewWidth control size small size
-- then a bold message
set {boldLabel, theTop} to create label "Send for output" bottom theTop + 8 max width accViewWidth control size regular size with bold type
-- make list of controls and pass to display command
set allControls to {theCheckbox, colorPopup, popupLabel, operatorField, operatorLabel, boldLabel, messageLabel}

-- create accessory view, passing controls plus size (as {width, height})
if current application's NSThread's isMainThread() as boolean then
	my createAccessoryViewMainThread:{allControls, {accViewWidth, theTop}}
else
	my performSelectorOnMainThread:"createAccessoryViewMainThread:" withObject:{allControls, {accViewWidth, theTop}} waitUntilDone:true
end if

-- now do the table
set emailList to {{}}

set popupList to {}
set myDate to (current date)
repeat with x from 1 to 5
	set myDate to myDate + 1 * days
	set the end of popupList to date string of myDate
end repeat
set defaultDate to item 1 of popupList
set tablePrompt to "Select the date, email addresses and indicate if there are ads on the page"
set selectedRows to {1, 2}

set theTable to make new table with data emailList ¬
	with title ¬
	"TV Highlights and grid pages" with prompt tablePrompt ¬
	multiple selections allowed true ¬
	can add and delete true ¬
	editable columns {1, 2} ¬
	column headings {"Label", "Address"} ¬
	row numbering false ¬
	initially selected rows selectedRows ¬
	without empty selection allowed

modify table theTable ¬
	OK button name ¬
	"Okay" cancel button name ¬
	"Cancel" extra button name ¬
	"Refresh" highlighted rows {} ¬
	alternate backgrounds false ¬
	row dragging false ¬
	without column reordering
modify table theTable accessory view theAccessoryView

set theAccessoryView to missing value -- to avoid error messages when saving

set tableResult to display table theTable ¬
	with extended results

on createAccessoryViewMainThread:theArg
	set {theControls, theSize} to theArg as list
	set my theAccessoryView to current application's NSView's alloc()'s initWithFrame:{{0, 0}, theSize}
	repeat with aControl in theControls
		(theAccessoryView's addSubview:aControl)
	end repeat
end createAccessoryViewMainThread:

This is excellent, Shane. I think I have two options that I can make work!

So it worked. Shane, thanks for the tools and the guidance!

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use script "Dialog Toolkit Plus"
use script "Myriad Tables Lib"
property theAccessoryView : missing value
property checkState : missing value

property emailList : {{"Email Name", "email@address.com"}, ¬
   {"Email Name", "email@address.com"}, ¬
   {"Email Name", "email@address.com"}, ¬
   {"Email Name", "email@address.com"}, ¬
   {"Email Name", "email@address.com"}, ¬
   {"Email Name", "email@address.com"}}

property selectedRows : {}
if selectedRows is {} then set selectedRows to {1, 2}

if checkState is missing value then set checkState to false

set popupList to {}
set myDate to (current date)
repeat with x from 1 to 7
   set myDate to myDate + 1 * days
   set the end of popupList to date string of myDate
end repeat
set defaultDate to item 1 of popupList
set selectedDate to defaultDate

set defaultEmailText to "Click 'Refresh' to see email text..."
set confirmationText to ""

repeat

   set accViewWidth to 420
   set theLabelStrings to {"Pub date:", "  Email Text:"}

   set maxLabelWidth to max width for labels theLabelStrings
   
   set controlLeft to maxLabelWidth + 8
   ---- then a small explanatory label
   --set {boldLabel, theTop} to create label " " bottom 0 max width accViewWidth control size regular size with bold type
   
   --  a labeled field
   set {operatorField, operatorLabel, theTop} to create top labeled field confirmationText placeholder text defaultEmailText bottom 0 field width accViewWidth extra height 60 label text "Email Text" with accepts linebreak and tab
   
   --  a checkbox
   set {theCheckbox, theTop, newWidth} to create checkbox "Page has other editorial" left inset controlLeft bottom (theTop + 20) max width accViewWidth initial state checkState
   
   --  a labeled popup
   set {colorPopup, popupLabel, theTop} to create labeled popup popupList left inset 20 bottom (theTop + 10) popup width 220 max width accViewWidth label text (item 1 of theLabelStrings) popup left controlLeft initial choice selectedDate
   -- make list of controls and pass to display command
   set allControls to {operatorField, operatorLabel, theCheckbox, colorPopup, popupLabel}
   
   -- create accessory view, passing controls plus size (as {width, height})
   if current application's NSThread's isMainThread() as boolean then
      my createAccessoryViewMainThread:{allControls, {accViewWidth, theTop}}
   else
      my performSelectorOnMainThread:"createAccessoryViewMainThread:" withObject:{allControls, {accViewWidth, theTop}} waitUntilDone:true
   end if
   
   -- now do the table
   
   set popupList to {}
   set myDate to (current date)
   repeat with x from 1 to 5
      set myDate to myDate + 1 * days
      set the end of popupList to date string of myDate
   end repeat
   set defaultDate to item 1 of popupList
   set tablePrompt to "Select the date, email addresses.
Indicate if there are ads on the page"
   
   set theTable to make new table with data emailList ¬
      with title ¬
      "TV Highlights and grid pages" with prompt tablePrompt ¬
      multiple selections allowed true ¬
      can add and delete true ¬
      editable columns {1, 2} ¬
      column headings {"Label", "Address"} ¬
      row numbering false ¬
      initially selected rows selectedRows ¬
      without empty selection allowed
   
   modify table theTable ¬
      OK button name ¬
      "Okay" cancel button name ¬
      "Cancel" extra button name ¬
      "Refresh" highlighted rows {} ¬
      alternate backgrounds false ¬
      initial position {30, 30} ¬
      row dragging false ¬
      without column reordering
   modify table theTable accessory view theAccessoryView
   
   set theAccessoryView to missing value -- to avoid error messages when saving
   
   set tableResult to display table theTable ¬
      with extended results
   
   set selectedRows to rows selected of tableResult
   set buttonClicked to button number of tableResult
   set emailAddresses to values selected of tableResult
   log emailAddresses
   set finalPosition to final position of tableResult
   set fullList to values returned of tableResult
   log tableResult
   
   set otherEdOnPage to theCheckbox's state() as boolean
   set theCheckbox to missing value -- to avoid error messages when saving
   set thePopup to missing value
   set pubDate to colorPopup's title() as text
   
   set selectedDate to pubDate
   if buttonClicked is 1 then
      exit repeat
   else if buttonClicked is 2 then
      set confirmationText to {"The TV grid and highlights page for " & pubDate & " is ready for print. ", ""}
      if otherEdOnPage then
         set checkState to true
         set the end of confirmationText to return & return & "The page has other editorial so I won't release."
      else
         set checkState to false
         set the end of confirmationText to return & return & "I can release when OK'd."
      end if
      
      set defaultEmailText to confirmationText as text
      set confirmationText to defaultEmailText
      
   else
      return tableResult
   end if
   
end repeat

on createAccessoryViewMainThread:theArg
   set {theControls, theSize} to theArg as list
   set my theAccessoryView to current application's NSView's alloc()'s initWithFrame:{{0, 0}, theSize}
   repeat with aControl in theControls
      (theAccessoryView's addSubview:aControl)
   end repeat
end createAccessoryViewMainThread:



1 Like

FWIW, you could also insert theCheckbox's setState:1 in there to get the checkbox selected initially. Strictly speaking it should be done on the main thread, but I suspect you can get away without the whole handler business.

It’s not checked on first run, which is fine, but it is checked on subsequent runs (since Properties still persist down here).

I’m using true and false rather than 1 and 0, but that’s fine, right?

I’m still tweaking, here’s the newest version.

But while we’re on the topic, when a row is added to a table is it possible to specify a default value? In this case it wouldn’t help that much, but I have other tables with multiple columns, but only one or two need to be changed from the default if the user adds a row.

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use script "Dialog Toolkit Plus"
use script "Myriad Tables Lib"

property theAccessoryView : missing value
property checkState : missing value

property selectedRows : {}
property emailList : {{}}

set rowTemplate to {{1, {"To", "cc", "bcc"}}, "", ""}

set subjectText to ""

if selectedRows is {} then set selectedRows to {1, 2}

if checkState is missing value then set checkState to false

set myDate to (current date)
set tableTitle to date string of myDate & ": TV Grid and Highlights page"
set pubDateList to {}
repeat with x from 1 to 7
   set myDate to myDate + 1 * days
   set the end of pubDateList to date string of myDate
end repeat
set defaultDate to item 1 of pubDateList
set selectedDate to defaultDate

set defaultEmailText to "Click 'Refresh' to see email text..."
set confirmationText to ""

repeat
   -- This code is from the Dialog Toolkit Plus sample "Aligned sample.scpt"
   set accViewWidth to 440
   set theLabelStrings to {"Pub date:", ("Email: " & subjectText)}
   
   -- to make it look better, we can get the length of the longest label we will use, and use that to align the controls
   set maxLabelWidth to max width for labels theLabelStrings
   set popUpLabel to ("Pick a date: ")
   
   set controlLeft to 8
   
   --  a labeled field
   set {operatorField, operatorLabel, theTop} to create top labeled field confirmationText placeholder text defaultEmailText bottom 0 field width accViewWidth extra height 50 label text ("Email: " & subjectText) with accepts linebreak and tab
   
   --  a checkbox
   set {theCheckbox, theTop, newWidth} to create checkbox "Page has other editorial" left inset controlLeft bottom (theTop + 20) max width accViewWidth initial state checkState
   
   set {colorPopup, popUpLabel, theTop} to create labeled popup pubDateList left inset 0 bottom (theTop + 20) popup width 220 max width accViewWidth label text popUpLabel popup left 0 initial choice selectedDate
   
   -- a spacer
   set {spacer, theTop} to create label " " bottom theTop + 0 max width accViewWidth control size regular size with bold type
   
   -- make list of controls and pass to display command
   set allControls to {operatorField, operatorLabel, theCheckbox, colorPopup, popUpLabel, spacer}
   
   -- create accessory view, passing controls plus size (as {width, height})
   if current application's NSThread's isMainThread() as boolean then
      my createAccessoryViewMainThread:{allControls, {accViewWidth, theTop}}
   else
      my performSelectorOnMainThread:"createAccessoryViewMainThread:" withObject:{allControls, {accViewWidth, theTop}} waitUntilDone:true
   end if
   
   set tablePrompt to "Select the date, email addresses.
   Indicate if there are ads on the page"
   
   set theTable to make new table with data emailList ¬
      with title tableTitle ¬
      with prompt tablePrompt ¬
      multiple selections allowed true ¬
      row template rowTemplate ¬
      can add and delete false ¬
      editable columns {1, 2, 3} ¬
      column headings {"cc", "Label", "Address"} ¬
      row numbering false ¬
      initially selected rows selectedRows ¬
      without empty selection allowed
   
   modify table theTable ¬
      OK button name ¬
      "Okay" cancel button name ¬
      "Cancel" extra button name ¬
      "Refresh" highlighted rows {} ¬
      alternate backgrounds false ¬
      initial position {30, 30} ¬
      row dragging false ¬
      without column reordering
   modify table theTable accessory view theAccessoryView
   
   set theAccessoryView to missing value -- to avoid error messages when saving
   
   set tableResult to display table theTable ¬
      with extended results
   
   set selectedRows to rows selected of tableResult
   set buttonClicked to button number of tableResult
   set emailAddresses to values selected of tableResult
   log emailAddresses
   set finalPosition to final position of tableResult
   set fullList to values returned of tableResult
   log tableResult
   
   set otherEdOnPage to theCheckbox's state() as boolean
   set theCheckbox to missing value -- to avoid error messages when saving
   set thePopup to missing value
   set pubDate to colorPopup's title() as text
   set pubDay to word 1 of pubDate
   set subjectText to pubDay & "'s TV Highlights are ready and the grid is on the page"
   set selectedDate to pubDate
   set confirmationText to {"The TV grid and highlights page for " & pubDate & " is ready for print. ", ""}
   if otherEdOnPage then
      set checkState to true
      set the end of confirmationText to return & return & "The page has other editorial so I won't release."
   else
      set checkState to false
      set the end of confirmationText to return & return & "I can release when OK'd."
   end if
   
   set defaultEmailText to confirmationText as text
   set confirmationText to defaultEmailText
   if buttonClicked is 1 then
      
      --return {confirmationText, subjectText, emailAddresses}
      
      exit repeat
   else if buttonClicked is 2 then
      
      set defaultEmailText to confirmationText as text
      set confirmationText to defaultEmailText
      
   else
      return tableResult
   end if
   
end repeat

set {toAddresses, ccAddresses, bccAddresses} to stripNamesFromAddresses(emailAddresses)
ComposeOutlookMessage(toAddresses, ccAddresses, bccAddresses, subjectText, confirmationText)

on createAccessoryViewMainThread:theArg
   set {theControls, theSize} to theArg as list
   set my theAccessoryView to current application's NSView's alloc()'s initWithFrame:{{0, 0}, theSize}
   repeat with aControl in theControls
      (theAccessoryView's addSubview:aControl)
   end repeat
end createAccessoryViewMainThread:


on ComposeOutlookMessage(toAddresses, ccAddresses, bccAddresses, messageSubject, messageBody)
   set messageBody to FixOutlookBodyText(messageBody)
   set AppleScript's text item delimiters to ""
   tell application "Microsoft Outlook"
      set the newMessage to (make new outgoing message with properties {content:messageBody, subject:messageSubject})
      repeat with thisAddressee in toAddresses
         make new recipient at newMessage with properties {email address:{name:"", address:thisAddressee}}
      end repeat
      repeat with thisAddressee in ccAddresses
         make new cc recipient at newMessage with properties {email address:{name:"", address:thisAddressee}}
      end repeat
      repeat with thisAddressee in bccAddresses
         make new bcc recipient at newMessage with properties {email address:{name:"", address:thisAddressee}}
      end repeat
      set thisMessage to open newMessage
      activate
   end tell
   
end ComposeOutlookMessage


on stripNamesFromAddresses(emailAddresses)
   log emailAddresses
   
   set {toAddresses, ccAddresses, bccAddresses} to {{}, {}, {}}
   set saveTID to AppleScript's text item delimiters
   set AppleScript's text item delimiters to {": "}
   repeat with thisAddress in emailAddresses
      set addressType to item 1 of thisAddress as text
      if addressType is "To" then
         set the end of toAddresses to item 3 of thisAddress as text
      else if addressType is "cc" then
         set the end of ccAddresses to item 3 of thisAddress as text
      else
         set the end of bccAddresses to item 3 of thisAddress as text
      end if
   end repeat
   set AppleScript's text item delimiters to saveTID
   return {toAddresses, ccAddresses, bccAddresses}
end stripNamesFromAddresses

on FixOutlookBodyText(textToFix)
   set textToFix to paragraphs of textToFix
   set saveTID to AppleScript's text item delimiters
   set AppleScript's text item delimiters to {"</P>" & return & "<P>"}
   set textToFix to textToFix as text
   set textToFix to "<P>" & textToFix & "</P>"
   set AppleScript's text item delimiters to saveTID
   return textToFix
end FixOutlookBodyText

You know, it could be possible to use a combination of the Extra button (or an accessory view) and √ boxes to allow a user to delete rows on the fly.

It works in that it gets converted to an integer when bridged, but using an integer is arguably more correct. Checkboxes aren’t always boolean in nature, in that they can be configured to have an indeterminate state (signified by a negative integer).

Sounds like a feature request.

Yes, come to think of it, that’s exactly what that sounds like :sunglasses:

yes, in one case I’ve used the extra button to do this, but in other cases I’ve run out of buttons so I guess I’ll have to dive into the murky world of accessory views. :grimacing: Thanks for the suggestion!

Here’s another question that could be come a feature request or two.

Is it possible for an MT table launched while a specific application is running to only be visible when that application is frontmost/active? Lots of apps have palettes that behave that way.

Ideally I’d like to have an MT Table that changes the displayed list based on which app is frontmost.

I’m using MT to create script palettes. I’m finding them potentially easier to use and definitely faster to execute than FastScripts; apple’s script menu or even script palettes and menus in some apps (inDesign; TextWranger; Script Debugger).

That’s something you have to control from your app. It’s not that hard to do — there’s a chapter about it in my book (chapter 16).

Feature request:

With empty selection allowed set to false, the extra button, if it is present, should still be enabled/clickable. Or at least the behaviour of the extra button should be controlled independently of the behaviour of the OK button.

But then empty selection would be allowed.

Can you give me examples of how that might be useful? It does add a significant amount of extra complication, so there’d have to be more value than just saving a follow-up dialog for invalid entry.

I often use the extra button as a “Refresh,” which gets a new set of table data to display.

For example, say the user is selecting a file to download from a list of files on the server. This would give the user the option of refreshing the list to see any new files added without having to select an item to download that the user doesn’t want to download.

It looks like if there are duplicate values in a popup menu in myriad tables, the first instance is removed, is that correct?

I’m trying to make this work easier for the user. Most of the selections in this list would Sunday’s; but a few of them would be weekdays (which may or may not include Sunday), and several would always be Wednesdays.

So the effect I’m trying to get is for the popup menu to display the next three Sundays; then every day of the week (including Sundays) below.

Instead it displays the full list without Sundays.

Is removing the first instance of duplicates at the beginning of a popup list intentional?

I’d prefer to display them with dupes, or if that’s not practical, keep the first instance and remove subsequent instances.

use scripting additions
use script "Myriad Tables Lib" version "1.0.7"
set rowTemplate to {"", {popup menu, {"Sunday, July 7, 2019", ¬
   "Sunday, July 14, 2019", ¬
   "Sunday, July 21, 2019", ¬
   "Sunday, July 7, 2019", ¬
   "Monday, July 8, 2019", ¬
   "Tuesday, July 9, 2019", ¬
   "Wednesday, July 10, 2019", ¬
   "Thursday, July 11, 2019", ¬
   "Friday, July 12, 2019", ¬
   "Saturday, July 13, 2019", ¬
   "Sunday, July 14, 2019", ¬
   "Monday, July 15, 2019", ¬
   "Tuesday, July 16, 2019", ¬
   "Wednesday, July 17, 2019", ¬
   "Thursday, July 18, 2019", ¬
   "Friday, July 19, 2019", ¬
   "Saturday, July 20, 2019", ¬
   "Sunday, July 21, 2019", ¬
   "Monday, July 22, 2019", ¬
   "Tuesday, July 23, 2019", ¬
   "Wednesday, July 24, 2019", ¬
   "Thursday, July 25, 2019", ¬
   "Friday, July 26, 2019", ¬
   "Saturday, July 27, 2019"}}}
set {dateList, firstSunday, firstWednesday, firstDate, sundayList} to {{"Sunday, July 7, 2019", ¬
   "Monday, July 8, 2019", ¬
   "Tuesday, July 9, 2019", ¬
   "Wednesday, July 10, 2019", ¬
   "Thursday, July 11, 2019", ¬
   "Friday, July 12, 2019", ¬
   "Saturday, July 13, 2019", ¬
   "Sunday, July 14, 2019", ¬
   "Monday, July 15, 2019", ¬
   "Tuesday, July 16, 2019", ¬
   "Wednesday, July 17, 2019", ¬
   "Thursday, July 18, 2019", ¬
   "Friday, July 19, 2019", ¬
   "Saturday, July 20, 2019", ¬
   "Sunday, July 21, 2019", ¬
   "Monday, July 22, 2019", ¬
   "Tuesday, July 23, 2019", ¬
   "Wednesday, July 24, 2019", ¬
   "Thursday, July 25, 2019", ¬
   "Friday, July 26, 2019", ¬
   "Saturday, July 27, 2019"}, ¬
   "Sunday, July 14, 2019", ¬
   "Wednesday, July 10, 2019", ¬
   "Monday, July 8, 2019", ¬
   {"Sunday, July 7, 2019", ¬
      "Sunday, July 14, 2019", ¬
      "Sunday, July 21, 2019"}}
set dateListPubList to {}

set the end of dateListPubList to {"What's on TV Coverage Plan", firstSunday}
set the end of dateListPubList to {"What's on TV", firstDate}
set the end of dateListPubList to {"Calendar Letters", firstSunday}
set the end of dateListPubList to {"What's on TV This Week", firstSunday}
set the end of dateListPubList to {"TV Ratings", firstWednesday}
set tableData to dateListPubList

set tableTitle to ""
set tableResult to display table with data tableData ¬
   with title tableTitle row template rowTemplate

return values selected of tableResult