I’ve just decided to start transforming my scripts to use more relative paths rather than hardcoded ones, and containing resources in the Contents/Resources/(custom folder) whenever possible. I want to plan my folder structures and locations better from scratch, and only these hardcoded paths have been keeping me from doing so.
I’ve been using external icons, sound effects and .plist files with my scripts for quite some time but I’m having trouble getting my handlers to work when using files embedded into the script app.
The strange thing is, I seem to get the same bit of script to work in one window, but as a part of a different script, it gives me “resource not found”.
Here’s my handler:
-----------------------------------------------------
# Handler for dialogs; Message, Answers, Icon, Default, Variable, Title (Embedded icon version)
-----------------------------------------------------
on dialog(themessage, theanswers, theicon, thedefault, thevariable, thetitle)
set embIcon to (path to resource theicon & ".icns" in directory "CustomContent") as string
tell application "System Events"
display dialog themessage buttons theanswers with icon file embIcon giving up after 20 default button thedefault with title thetitle
set thevariable to the button returned of the result
end tell
end dialog
Here’s a call:
set theAvailable to {"Morning", "Day", "Evening"} --available answers get defined earlier in the script based on certain conditions, and that's why the dialog refers to answers as a variable
set b_timeofday to dialog("What time?", theAvailable, "TimeOfDay", "Day", "b_timeofday", "Define time") ---Assuming that TimeOfDay.icns exists at Contents/Resources/CustomContent
I’ve been using this same scheme for ages and the only difference between the old and this new version is that in the handler, the folder path of where the icon would be found used to point into some absolute folder location.
Why would this version now arbitrarily seem to “not find the resource”?
No need here tell application “System Events” at all.
Script needs to know what application’s bundle “CustomContent” is ( that is, needs full path)
So, here Need:
set my_Directory to choose file -- choose here bundle you need. This gives you alias of bundle
set embIcon to path to resource theicon & ".icns" in bundle my_Directory
For example, in Safari:
set embIcon to path to resource "Error.png" in bundle alias "Untitled:Applications:Safari.app:"
For files, embeded in current script app:
set embIcon to path to resource theicon & ".icns" in bundle (path to me)
NOTE: In case of script applet you can see result in Script Debugger. First you save script as applet
You need to use entire pathname but you have to need to hardcode it.
Happily, the script is able to build it by itself as you may check after saving the script below as an application.
set myPath to path to me
set myContents to ((myPath as text) & "Contents:") as alias
tell application "Finder"
set level2 to entire contents of myContents
end tell
set level2Alt to {}
repeat with i from 1 to count level2
try
set end of level2Alt to (item i of level2) as alias
(* Fails upon: "PkgInfo", "applet", "applet.icns", "applet.rsrc" *)
end try
end repeat
level2Alt
display dialog my recolle(level2Alt, linefeed)
(*
Return something like :
"SSD 500:Users:*********:Desktop:test.app:Contents:Info.plist
SSD 500:Users:*********:Desktop:test.app:Contents:MacOS:
SSD 500:Users:*********:Desktop:test.app:Contents:Resources:
SSD 500:Users:*********:Desktop:test.app:Contents:Resources:Scripts:
SSD 500:Users:*********:Desktop:test.app:Contents:Resources:description.rtfd:
SSD 500:Users:*********:Desktop:test.app:Contents:Resources:Scripts:main.scpt"
*)
#=====
on recolle(l, d)
local oTIDs, t
set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
set t to l as text
set AppleScript's text item delimiters to oTIDs
return t
end recolle
#=====
Honestly, I don’t know what let you think that you may use relative pathnames.
Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) samedi 4 mai 2019 17:45:09
(Edit: I was writing this response while there had only been one response so far; When I posted this, Yvan had apparently written a response meanwhile! So this comment was to the first response and Yvan I’ll get back to yours in a bit, not skipping it on purpose or anything!)
It’s actually there on purpose: I’m developing a physical input device and it’s programmed by using software whose helper then runs as a background process to either do logic or trigger tasks. In most of my use, the software runs Applescripts upon key press, keys that aren’t a part of the normal keyboard. If dialogs were not wrapped in ‘tell application “System Events”’, it caused the dialogs to appear with no interface and with no chance of bringing them visible or interacting with them.
I also often run dialog-containing scripts from the scripts menu when I’m doing other stuff, and without the ‘system events’ wrapper, sometimes the dialog would be displayed behind other windows so I had to click the app’s icon in the dock in order to bring it forward. So the wrapper really is there on purpose.
I’m not sure I understand the script examples there; I copied the first one into the handler and got the same error, then tried the last one and got the same result.
I kept playing around and this seems to do it:
set embIcon to ((path to me as string) & "Contents:Resources:CustomContent:" & theicon & ".icns")
However, I still don’t quite understand why my first version was only working in some script but not another. And, in this script with the issue, all this time I was able to successfully link to a resource which wasn’t an icon but a .plist. i.e this one worked just fine all the time:
set embTimeOfDay to POSIX path of (path to resource "Time Of Day.plist" in directory "CustomContent")
But why it can be file format specific, I wonder… The .plist line isn’t a part of a handler but the icon with a dialog is.
set myPath to path to me
set theIcon to "custom" # Edit to fit your needs
set thePlist to "custom" # Edit to fit your needs
set myCustomContents to ((myPath as text) & "Contents:Resources:CustomContents:")
set path2MyIcon to myCustomContents & theIcon & ".icns"
set path2MyPlist to myCustomContents & thePlist & ".plist"
tell application "Finder"
open path2MyIcon as alias
open path2MyPlist as alias
end tell
Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) samedi 4 mai 2019 18:53:07
You must understand that: if resource is in bundle, and if is in directory (simple folder) this is different things. Bundle is file, not directory. So, you command “in directory” will work only for resources whose container is some simple folder, and command “in bundle” will work only for resources whose container is some bundle. All applications is bundles. Check this: you can select bundle only with choose file command and can’t with choose folder command.
It seems, you plist file is inside folder, and you .icn file is inside application or script bundle. So, for plist in directory should work, but no for .icn file. My script examples above is for normal OS X bundles (applications)
So, NOT in directory, fuck in directory. Use general way for both bundles and folders – aliases!
Command resource to always needs properly provided target. Implicit this can happen be other target inside handlers, so check that things too.
To display dialogs on front no need tell application "System Events". You can put before your display dialog commands this:
tell me to activate
To test, quit Safari and run this script:
set safari_Path to path to application "Safari"
tell application "Safari" to activate
delay 5
set embIcon to (path to resource "Error.png" in bundle safari_Path) as string
tell me to activate
display dialog "I am Error Icon" buttons {"OK"} with icon file embIcon giving up after 20 default button "OK" with title "My Icon Message"
set thevariable to the button returned of the result