"giving up after" command not fully working in Mavericks - applescript

I encountered a mysterious bug with AppleScript and OSX 10.9.1.
This code works inside AppleScript Editor, but when I save it as an application, "giving up after" doesn't work. It works in my other computer with 10.6.8 (Snow Leopard) though. Does anyone know what's the issue? Thanks!
global fullTime
global chosenTime
set pickFromList to {1, 2}
choose from list the pickFromList with prompt "Next message will dissapear after 1 + x seconds. Choose x!"
set chosenTime to result as text
add1sec()
display dialog "Click OK and the next dialog box will appear in " & fullTime & " seconds"
delay fullTime
display dialog "Works! But now this should dissapear after " & fullTime & " seconds" giving up after fullTime
on add1sec()
set fullTime to chosenTime + 1
end add1sec

I would write it like this:
set pickFromList to {1, 2}
set chosenTime to (choose from list the pickFromList with prompt "Next message will dissapear after 1 + x seconds. Choose x!") as number
set fullTime to add1sec(chosenTime)
display dialog "Click OK and the next dialog box will appear in " & fullTime & " seconds"
delay fullTime
tell application "SystemUIServer" to display dialog "Works! But now this should dissapear after " & fullTime & " seconds" giving up after fullTime
on add1sec(startTime)
return startTime + 1
end add1sec

Hmm, this actually did solve the "giving up after" -problem, but it also created another one. Now that this is used:
tell application "SystemUIServer" to display dialog "Works! But now this should disappear after " & fullTime & " seconds" giving up after fullTime
First of all, the dialog box is not "connected" to the running application anymore, so that I can't make it active by clicking the application icon in dock. Second, if "giving up after" is longer than 2 minutes the default timeout occurs.

Updating to OSX 10.9.2 fixed this issue.

Related

Making a dialog that bugs me in Applescript

I know this question is kinda messy. I don't know how to make it more specific. I want to make an applescript that asks me every hour what I've been doing for the past hour.
The issue I'm having is that I want it to pop up, make a sound, and wait for my response. If I do a normal dialog, and I'm busy, it will go behind the other windows on my mac. I thought maybe having a persistent banner notification would be great, but applescript doesn't allow for much control over banners.
I want something to float over all windows so that I can see that the applescript has been waiting for a response from me until I fill out the dialog.
What you're looking for is a global floating window, similar to what LittleSnitch does. You can do that, but not with pure AppleScript. You'd have to write a Cocoa app.
Adding an activate command just before a display dialog command in your AppleScripts, will ensure the pop-up dialog window will become frontmost and visible no matter what other apps and documents are currently opened (until another app or document gets activated, thus bringing that item to the front).
This following AppleScript may be of some use to you.
Save this following AppleScript code as a "stay open application" in Script Editor.app.
When running your new AppleScript applet, it will remain running (because it has an idle handler) until you press "Cancel" in any of the dialog pop-ups or choosing to quit the app in the Dock.
This code also logs everything it receives in the dialog pop-ups, to file for you.
property myComputerActivitiesLog : (path to desktop as text) & "My_Computer_Activities.log"
property theDialog : missing value
property theDate : missing value
property insertTime : missing value
property logContent : missing value
on idle
set theDate to (current date)
set insertTime to " ------ " & theDate & " ------ "
beep 5
say "It's time to log your activities"
activate
try
set theDialog to display dialog ¬
"Itemize my activities." default answer ¬
"Itemize my activities for yhe past hour." & linefeed & linefeed ¬
buttons {"Cancel", "OK"} default button 2 cancel button 1 ¬
with title "Account For My Activities" with icon 1
end try
if theDialog = missing value then
quit me
else
set logContent to insertTime & linefeed & (text returned of theDialog) & linefeed
do shell script "echo " & quoted form of logContent & ¬
" >> " & quoted form of POSIX path of myComputerActivitiesLog
set theDialog to missing value
return 3600 -- in seconds
end if
end idle
on quit -- Executed when the script quits
-- Additional code to perform (if any) goes here
continue quit -- allows the script to quit
end quit

How to make application written using AppleScript to open the dialog each time the icon is clicked?

I'm writing an applescript application that would say time every 5 mins. This will be in an infinite loop. My requirement is, although it is running 24x7 since start, next time when I click application icon, it should show the dialog to get user input via one of the 3 buttons.
I have 3 buttons.
Pause Notifications
Notifications ON
Notification OFF
When the code is in infinite loop, and I click the application icon, the dialog prompt doesn't come up to get the user input via above 3 buttons. How to fix that?
global isSoundEnabled, isNotifEnabled
on run
set isSoundEnabled to true
set isNotifEnabled to true
set theDialogText to "The curent date and time is " & (current date) & "."
display dialog theDialogText buttons {"Pause", "Notif ON", "Notif OFF"} default button "Notif ON" cancel button "Pause" with icon caution
if result = {button returned:"Notif ON"} then
set isSoundEnabled to true
set isNotifEnabled to true
loop()
else if result = {button returned:"Notif OFF"} then
set isSoundEnabled to false
set isNotifEnabled to false
end if
end run
on loop()
repeat while true
set min to getMin()
get min as integer
#if (min mod 5) = 0 then
if (min / 5) > 1 then
set timee to getTimeInHoursAndMinutes()
if isNotifEnabled then
display notification timee
end if
if isSoundEnabled then
say timee
end if
#delay 60
#if isSoundEnabled is not
end if
#exit repeat
end repeat
end loop
I haven't added getTimeInHoursAndMinutes() and getMin() implementation on purpose as it doesn't much value.
The application user interface (menus, etc) will be blocked if you don’t give the system time to process events, so you want to avoid long repeat loops. The standard dialogs are modal, so you also normally can't do other things while they are being shown.
Repeatedly showing the standard dialogs can also be intrusive, since the current application will switch if activating the application (to show the dialog), or the Dock icon will start bouncing if you don't. Some AppleScriptObjc could be used for other types of notifications, but for this example I stayed with the standard dialogs.
I did cheat a little in the following script by using some AppleScriptObjC for the speech synthesizer, since it can speak in the background (while a dialog is shown). I've also avoided using notifications, since those need to be allowed in the System Preferences.
The bottom line is that when saving an app as stay open, the idle and reopen handlers can be used - the idle handler is repeatedly called after the run handler finishes (it uses a timer), and the reopen handler is called when the app is double-clicked (or the Dock icon clicked), so you can avoid locking up the UI. For example:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "AppKit" -- for the speech synthesizer
use scripting additions
global isSoundEnabled, isNotifEnabled, defaultButton
on run -- initial setup
set isSoundEnabled to true
set isNotifEnabled to true
set defaultButton to "Notif OFF" -- the default is set opposite the current setting
getSettings()
end run
to getSettings()
set theDialogText to "The curent date and time is " & (current date) & "."
tell me to activate
set theButton to button returned of (display dialog theDialogText buttons {"Quit", "Notif ON", "Notif OFF"} default button defaultButton with icon caution giving up after 10)
if theButton is "Notif ON" then
set isSoundEnabled to true
set isNotifEnabled to true
set defaultButton to "Notif OFF"
else if theButton is "Notif OFF" then
set isSoundEnabled to false
set isNotifEnabled to false
set defaultButton to "Notif ON"
end if
end getSettings
on reopen -- application double-clicked or dock icon clicked
getSettings()
end reopen
on idle -- after the run handler completes, is called repeatedly
set giveup to 5 -- dialog will self-dismiss, although timing will be a little off if manually dismissed
set theTime to time string of (current date)
if isSoundEnabled then -- AppleScriptObjC is used to speak in the background
(current application's NSSpeechSynthesizer's alloc's initWithVoice:(missing value))'s startSpeakingString:theTime
end if
if isNotifEnabled then
tell me to activate
display dialog "The current time is " & theTime with title "Current time" buttons {"OK"} giving up after 5
end if
return 300 - giveup -- the number of seconds for next idle run (less the dialog giveup time)
end idle

How do I get a dialog input with 2 buttons to auto execute after timeout if no input action?

I load an automator.app on my MacBook on startup that connects my MacBook to my local server. I created it with a dialog box that allows me to 'connect' or 'cancel' this script. This has been working, but at times I wish it would automatically input "connect" after 60 seconds.
I'm not really versed in AppleScript and have build most of my automator (app) routines I use from information I find on the internet and modify until it works. The following code works, sort of. It redraws the dialog box ever 5 seconds and I just want the numerics (wait_time variable) updated without a complete redraw of the dialog box. If I can do that I can have it update every 1 second. Next and more important, when I select the default button "Connect Now" nothing happens. The "Don't Connect" button seems to work fine. After this part of the script runs, I connect to specific folder on my local server and all of that works fine.
set theDialogText1 to "You will be connected to the Local Server in "
set wait_time to "60"
set theDialogText2 to " seconds. If your are not on the Local network; select [Don't Connect]."
repeat wait_time times
display dialog theDialogText1 & wait_time & theDialogText2 buttons {"Don't Connect", "Connect Now"} default button "Connect Now" cancel button "Don't Connect" giving up after 5
set wait_time to wait_time - 5
end repeat
I would like this to function like the 'shut down' dialog works in macOS.
Display what is happening, offer a button to run the action sooner, offer a button to cancel the function, and run the function automatically in 60 seconds if no input is received.
Applescript only offers simple dialog, then you can't display a count down of remaining seconds with simple Applescript command. There is a progression bar display, but that display has no button.
The easiest is to use a standard dialog box with instruction "giving up after x" which closes the dialog after x seconds if the user does not react before. You just have to check if the dialog has been closed with the gave up boolean = true or check which button has been used to close it. The script bellow handles the 3 cases (waiting time 3 seconds for test)
set wait_time to 3
set feedback to display dialog "test time out" buttons {"Don't connect", "Connect"} giving up after wait_time
if gave up of feedback then
display alert "no user action after " & wait_time & " seconds."
else if button returned of feedback is "Connect" then
display alert "User clicks on Connect"
else
display alert "User clicks on don't connect"
end if
You can also put this in an handler (= sub routine) and set wait_time to 3 seconds and call it several times. The script becomes a bit more complex, this is why I added few comments :
set Refresh_time to 3 -- the delay between 2 refresh of the dialog
set wait_time to 21 --total delay for user to decide
set Decision to 0
repeat until (Decision > 0) or (wait_time = 0)
set Decision to Get_User_Feedback(wait_time, Refresh_time)
set wait_time to wait_time - Refresh_time
end repeat
display alert "Decision is " & Decision
-- 0 means no answer
-- 1 means Connect
-- 2 means don't connect
-- your program here
on Get_User_Feedback(Remain_time, Step_delay)
set feedback to display dialog "Do you want to connect. Time left is " & Remain_time & " Sec." buttons {"Don't connect", "Connect"} giving up after Step_delay
if gave up of feedback then
return 0
else if button returned of feedback is "Connect" then
return 1
else
return 2
end if
end Get_User_Feedback
the Get_User_Feedback is called several times in the repeat loop. It displays the dialog for 3 seconds, then close and recall again showing the new remain time. After total wait_time, or if user uses a button before, the repeat loop stops.

Applescript changes?

I have a problem with an applescript on an iMac I am upgrading at work, this is below, it stops at:
error number -1719 from text field 1 of window 1 of process "QuarkXPress"
The full script I am trying to run:
try
tell application "FileMaker Pro Advanced"
--tell database "artdb_Client"
set theRecord to current record of database "artdb_Client"
tell theRecord
set theCustomer to item 4
set theCustomerName to item 5
set theFileName to item 2
end tell
--end tell
end tell
tell application "QuarkXPress"
activate
display dialog ¬
theCustomer & " - " & theCustomerName default answer theCustomer buttons {"Cancel", "OK"} default button 2 ¬
with title "Enter the Customer Code for Job"
(*
display dialog ¬
theCustomer & " - " & theCustomerName & ¬
"?" with title "Export PDF for Customer"
*)
end tell
set theFolder to "Data HD:Proofs:" & theCustomer
set theFolderOfPosix to "/volumes/Data HD/Proofs/" & theCustomer
set this_item to theFolder & ":" & theFileName & ".pdf"
set theProofsDir to "Data HD:Proofs:" as alias
tell application "System Events"
tell process "QuarkXPress"
tell menu bar 1
tell menu bar item "File"
tell menu "File"
tell menu item "Export"
tell menu "Export"
click menu item "Layout as PDF..."
delay 1
end tell
end tell
end tell
end tell
end tell
end tell
repeat 5 times
tell process "QuarkXPress"
if window "Export as PDF" exists then
keystroke "G" using command down
set value of text field 1 of window 1 to theFolderOfPosix & "/"
keystroke return
click button "Go" of window 1
exit repeat
else
delay 1
end if
end tell
delay 1
end repeat
end tell
end try
I finally got it to work, where the script was stopping (without putting the called data in):
set value of text field 1 of window 1 to theFolderOfPosix & "/"
I changed it to:
set value of text field 1 of sheet 1 of window 2 to theFolderOfPosix & "/"
Thanks to UI Browser for showing me the "sheet" field I was missing, it doesn't look right but it does the job so that's all that matters I guess.
You need to provision YOUR.app for UI Scripting (Accessibility support) in the Security pane of the System Preferences. There is a good writeup on how that works here: AppleScript System Notifications Support (advanced). That is, it describes the steps necessary to make ui scripting work.
HTH

applescript screen-shot automator buggy when exported as .app

so, I am making an app that takes screenshots at a regular interval for a customizable amount of time. I'm having a hard time with it because when I run the app in the applescript editor, everything is fine - but when I export it to an .app, things are buggy, and if the user clicks on the app icon, it will trigger the "repeat" code, and if the user tries to quit, it behaves erratically.
I read in other posts that on idle could work, but I don't know how to end an idle handler after a specified amount of time.
Anybody knows the solution to my conundrum? Thank you!
on run
set frequencyList to {2, 5, 10, 15}
set durationList to {30, 60, 90, 120, 150, 180}
choose from list durationList with prompt "how long (in minutes) would you like to snap screenshots for?"
set chosenDuration to result as number
set chosenDurationSeconds to chosenDuration * 60
choose from list frequencyList with prompt "how often (in minutes) would you like to snap a screenshot?"
set chosenFrequency to result as number
set chosenFrequencySeconds to chosenFrequency * 60
set repeatNumber to chosenDurationSeconds / chosenFrequencySeconds
display dialog "Great! I'll take " & repeatNumber & " photos over the span of " & chosenDuration & " minutes."
display dialog "Next, choose where you want these to end up."
set FolderPath to POSIX path of (choose folder) as string
display dialog "Sounds good! Just let me run in the background, and I'll snap away until the time is up."
delay 1
repeat repeatNumber times
set theCurrentDate to current date
set shellCommand to "/usr/sbin/screencapture \"" & FolderPath & "Screen Shot" & theCurrentDate & ".png\""
do shell script shellCommand
delay chosenFrequencySeconds
end repeat
end run
Here's how you would write your code with an "on idle" handler (I didn't test it). Remember to save this as a "stay open application". Notice that you tell the on idle handler to repeat in seconds in the last line of the handler. Notice also that we quit the app at the calculated date rather than repeating a number of times. You could essentially make a counter to count the loops of the idle handler but the date method is easier. Finally notice we have global variables. This makes the variables initiated in the on run handler available to the on idle handler.
Good luck.
global quitTime, chosenFrequencySeconds, FolderPath
on run
set frequencyList to {2, 5, 10, 15}
set durationList to {30, 60, 90, 120, 150, 180}
choose from list durationList with prompt "how long (in minutes) would you like to snap screenshots for?"
set chosenDuration to result as number
set quitTime to (current date) + chosenDuration * minutes
choose from list frequencyList with prompt "how often (in minutes) would you like to snap a screenshot?"
set chosenFrequency to result as number
set chosenFrequencySeconds to chosenFrequency * 60
display dialog "Great! I'll take " & repeatNumber & " photos over the span of " & chosenDuration & " minutes."
display dialog "Next, choose where you want these to end up."
set FolderPath to POSIX path of (choose folder) as string
display dialog "Sounds good! Just let me run in the background, and I'll snap away until the time is up."
delay 1
end run
on idle
set theCurrentDate to current date
set shellCommand to "/usr/sbin/screencapture " & quoted form of (FolderPath & "Screen Shot" & (theCurrentDate as text) & ".png")
do shell script shellCommand
if theCurrentDate is greater than or equal to quitTime then tell me to quit
return chosenFrequencySeconds
end idle
Maybe you should try to implement a reopen handler. I have done so with regulus's code, and it worked for me, if the applet is installed in the dock, then it starts the first, time, if it is clicked later on, you'll get a message that it is already running. The reopen handler probably have some superfluos code, like testing for if the app is running, and activating it, since the reopen handler should only be triggered when the app is already running. But I'll leave that for you, at least it doesn't execute the run handler now. :)
global quitTime, chosenFrequencySeconds, FolderPath
on run
set frequencyList to {2, 5, 10, 15}
set durationList to {30, 60, 90, 120, 150, 180}
choose from list durationList with prompt "how long (in minutes) would you like to snap screenshots for?"
set chosenDuration to result as number
set quitTime to (current date) + chosenDuration * minutes
choose from list frequencyList with prompt "how often (in minutes) would you like to snap a screenshot?"
set chosenFrequency to result as number
set chosenFrequencySeconds to chosenFrequency * 60
display dialog "Great! I'll take " & chosenFrequency & " photos over the span of " & chosenDuration & " minutes."
display dialog "Next, choose where you want these to end up."
set FolderPath to POSIX path of (choose folder) as string
display dialog "Sounds good! Just let me run in the background, and I'll snap away until the time is up."
delay 1
end run
on idle
set theCurrentDate to current date
set shellCommand to "/usr/sbin/screencapture " & quoted form of (FolderPath & "Screen Shot" & (theCurrentDate as text) & ".png")
do shell script shellCommand
if theCurrentDate is greater than or equal to quitTime then tell me to quit
return chosenFrequencySeconds
end idle
on reopen
if running of me then
tell me
activate
display alert "Already running"
end tell
end if
end reopen

Resources