I have three scripts {“A”, “B”, “C”} in the AppDelegate.applescript, where B and C control two different DropBoxes and A controls the rest of the UI. Basically when an item is dropped on the DropBoxes they return the path of the item dropped, setting respectively the URL in the variables theItem1 and theItem2.
I want to make those variables readable by the script A.
I tried with this:
global theItem1
global theItem2
script A
property parent : class "NSObject"
property theItem1 : missing value
property theItem2 : missing value
on applicationWillFinishLaunching_(aNotification)
my dropBox1's registerForDraggedTypes_({"public.file-url"})
my dropBox2's registerForDraggedTypes_({"public.file-url"})
end applicationWillFinishLaunching_
end script
script B
property parent : class "NSBox"
property theItem1 : missing value
on draggingEntered_(sender)
log "entered"
set pb to sender's draggingPasteboard()
set theOptions to {NSPasteboardURLReadingFileURLsOnlyKey:1}
return pb's canReadObjectForClasses_options_({current application's |NSURL|}, theOptions)
end draggingEntered_
on performDragOperation_(sender)
log "perform"
-- Get the file paths
set pb to sender's draggingPasteboard()
set theOptions to {NSPasteboardURLReadingFileURLsOnlyKey:1}
set theItem1 to pb's readObjectsForClasses_options_({current application's |NSURL|}, theOptions)
return true
end performDragOperation_
end script
script C
property parent : class "NSBox"
property theItem2 : missing value
on draggingEntered_(sender)
log "entered"
set pb to sender's draggingPasteboard()
set theOptions to {NSPasteboardURLReadingFileURLsOnlyKey:1}
return pb's canReadObjectForClasses_options_({current application's |NSURL|}, theOptions)
end draggingEntered_
on performDragOperation_(sender)
log "perform"
-- Get the file paths
set pb to sender's draggingPasteboard()
set theOptions to {NSPasteboardURLReadingFileURLsOnlyKey:1}
set theItem2 to pb's readObjectsForClasses_options_({current application's |NSURL|}, theOptions)
return true
end performDragOperation_
end script
But when I try to get the variables by the script A I get this:
You can’t use script objects and globals like that in an Xcode project.
When you define “script A”, what happens is that when the script loads, a new Objective-C class is created, called A, and set up so that it has methods that match and call your code. The same thing will happen with script B and script C – you will end up with three unrelated classes. And because you have effectively deleted AppDelegate.applescript, your links to the delegate in the interface will also be broken.
The fact that B and C are both subclasses on NSBox is a bit confusing – you probably only need one subclass, which you can use for multiple boxes.
To communicate between the classes, you will need either to make outlets in the interface, or perhaps talk to the App delegate class. Either way you need to use method calls, like theItem() and setTheItem_().
The problem is that if I use only one subclass how can I set a variable different for each drop box?
And I don’t understand if it is better whether I create new files called “B.applescript” and “C.applescript” or just leave them as they are? Namely all in a file?
You use separate outlets for them in your app delegate script. You only need one class file for multiple instances.
Let’s say you have a handler in your app delegate like this:
on wasDropped_sender_(itemDropped, sender)
log itemDropped
if sender = dropBox1 then -- where dropBox1 is a property/outlet to a subclassed box
log "dropBox1"
else
-- whatever
end if
end wasDropped:sender:
And then in your box subclass you call:
current application’s NSApp’s delegate()'s wasDropped_sender_(theItem1, me)
I prefer them separate, just because it becomes easier if the file gets too big. But functionally it’s the same.
What you shouldn’t do, though, is give them names like A or B. Leave the appDelegate what it was originally, and use descriptive names like MyBoxSubclass or MyDropBox for others.
I haven’t given them names like those, I wrote so just for example…
Anyway I tried your handler and code looks like this:
script AppDelegate
property parent : class "NSObject"
-- IBOutlets
property window : missing value
property dropBox1 : missing value
property dropBox2 : missing value
on applicationWillFinishLaunching_(aNotification)
my dropBox1's registerForDraggedTypes_({"public.file-url"})
my dropBox2's registerForDraggedTypes_({"public.file-url"})
end applicationWillFinishLaunching_
on wasDropped_sender_(itemDropped, sender)
log itemDropped
if sender = dropBox1 then
log "dropBox1"
else
log "dropBox2"
end if
end wasDropped_sender_
on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_
end script
script MSDropBox
property parent : class "NSBox"
property theItem1 : missing value
on draggingEntered_(sender)
log "entered"
set pb to sender's draggingPasteboard()
set theOptions to {NSPasteboardURLReadingFileURLsOnlyKey:1}
return pb's canReadObjectForClasses_options_({current application's |NSURL|}, theOptions)
end draggingEntered_
on performDragOperation_(sender)
log "perform"
-- Get the file paths
set pb to sender's draggingPasteboard()
set theOptions to {NSPasteboardURLReadingFileURLsOnlyKey:1}
set theItem1 to pb's readObjectsForClasses_options_({current application's |NSURL|}, theOptions)
log theItem1
log sender
current application's NSApp's delegate()'s wasDropped_sender_(theItem1, me)
return true
end performDragOperation_
end script
But doesn’t work (probably I put the handler in the wrong place).
The subclass doesn’t recognize the sender, in fact the App Delegate returns always “dropBox2”.
How can I coerce the file path as text?
Because If I try to coerce it as text I get “Can’t make «class ocid» id «data optr00000000B0BB040000600000» into type text. (error -1700)”
You can either coerce the array to a list, and then get the path of each item, or you can use valueForKey:“path”, and coerce the result to a list after.
Hi Shane,
today, checking that everything was working well, I noticed that one thing doesn’t.
I have this:
on wasDropped_sender_(itemDropped, sender)
log itemDropped
if sender's title() as text = "Box1" then
log "dropBox1"
set theItem1 to itemDropped as text
set theItem1 to theItem1 & "/"
log theItem1
set theItem1 to posix file theItem1 --this gives an error
log theItem1
tell application "Finder" to set labelSource to label index of theItem1 --this doesn't work because requires an alias
else
log "dropBox2"
set theItem2 to itemDropped as text
end if
end wasDropped_sender_
I need to convert that text as alias, in order to make the Finder working with the label.
The first error is <AppDelegate @0x60000022ffc0: OSAID(8) ComponentInstance(0x810000)>
and the second is *** -[AppDelegate wasDropped:sender:]: Can’t get «class labi» of class “NSObject”. (error -1728)
If you read my book, you’d save yourself a lot of time. Just sayin’.
You can’t use certain terms like POSIX file like that – you have to use as POSIX file.
But why bother with all that, when you can use NSURL?
set anNSURL to current application's |NSURL|'s fileURLWithPath:theItem1
set {theResult, labelSource} to anNSURL's getResourceValue:(reference) forKey:NSURLLabelNumberKey |error|:(missing value)
And you only need half that code because you threw the NSURL away in the first place.
I haven’t bought your book so far because I’m italian and i’m afraid that I’m buying a book I can’t understand…
However I’m gonna try this and give you some feedback.
Si, capisco. I’m sure it must be much harder doing this stuff for non-English-speakers. But for what it’s worth, the book does come with a lot of code, which is the same in any language (although again, it must be hard when the method names are often meaningless).
And you’re free to ask questions about the book here, too. Maybe Stefano will step in and answer.