PathControl challenges

Hello,

I have been putting an interface on my applescript of about 200 lines and have been successful in having it run headless in XCode once loaded so all is well with the code at this point after some tweaking.

The app has the both a file’s path and it’s name hard coded as separate properties and I would like to add them as choices for the user in the interface but am having many challenges even after having read as much documentation as I could find. The app also has the same 2 properties for an application path and it’s name that the same issue would apply to. One I get this worked out the other should be the same solution.

Although I have bound the pathControl to both the IBOutlets and an IB Action as well as the app delegate to the pathControl instance in the window, I am only getting the file path as “file://localhost/Users/username/Desktop/my%20%folder/thefile.txt” and would like to see it as /Desktop/my folder/thefile.txt. Also I can’t seem to get the name of the file that the path is pointing to separately (thefile.txt). I have followed the tutorials and gleened some hints from them for this issue but still seem far from a solution.

I hope I am explaining this well, here is the code so far for this pathControl:


script AppDelegate
property parent : class "NSObject"

-- IB Outlets
property filepathControl : missing value
property apppathControl : missing value

property filePath : missing value
property myFile : missing value

--IB Actions
 on setFilepathFromFilePathControl_(sender)
	set filepath to filepathControl's stringValue()
	set myFile to filepathControl's URL {}
 end setFilepathFromFilePathControl_


Once run, setting the path in the interface I get “file://localhost/Users/username/Desktop/my%20%folder/thefile.txt” for the filePath property but nothing for the myFile property.

Also I get this from the debugger console:
AppDelegate setFilepathFromFilePathControl:]: Can’t get «class url » {} of «class ocid» id «data kptr0000000060D0920002000000». (error -1728)

and this from Console’s system log:
Can’t get «class url » {} of «class ocid» id «data kptr0000000060D0920002000000». (error -1728)

I am very new to ApplescriptOBJC, no Studio experience, but have been using Applescript for years. Looking forward to taking the next step.
Thanks again for any assistance.

You’ve hit a couple of problems. First, the URL method’s name clashes with AS terminology, so when you type:

set myFile to filepathControl’s URL()

it gets changed to:

set myFile to filepathControl’s URL {}

The solution is to use pipes:

set myFile to filepathControl’s |URL|()

Unfortunately there doesn’t seem to be a simple AS way to convert a file URL to a path, but you can use an ObjC method, called “path”. That’s a terminology clash to, so you end up with something ugly like:

set myFile to |path|() of filepathControl’s |URL|()

It’s a work of beauty to me after so many hours looking for the solution! Thank you so much Shane.

Also is there a method to get the file’s name? I tried many variations but was not successful, the most promising seemingly the lastItem value, but not receiving it, I suspect another terminology clash?

I have tried:

set fileName to lastItem(filepathControl’s |URL|())

and

set fileName to filepathControl’s lastItem()

… but neither work.

Would this be the same issue? and can I still include it in the same Handler/IB Action as follows?


on setFilepathFromFilePathControl_(sender)
         set filePath to |path|() of filepathControl's |URL|()   -- file's path
         set myFile to filepathControl's lastItem ()                -- file's name
end setFilepathFromFilePathControl_

Again, many thanks

The thing to do in cases like this is to call up Xcode’s help and search for the class – in this case, URL should take you to NSURL. There you’ll see all the instance methods, including one called lastPathComponent.

Thanks, that worked, but as feared opened up still more issues related to paths.

set my theFile to lastPathComponent of |path|() of filepathControl’s |URL|()
… i s what it looks like in the code now. It is a text string and I can use it in my code routinely.

However, regarding paths, all I used to do in my script was place the path from my first post (filePath) in the property, and :


set fullfilePath to filePath as alias
		tell application "System Events"
			set modDate to modification date of fullfilePath
		end tell

Now this doesn’t work either. Looking in the log the property is a POSIX path, but no matter what I have tried I can’t convert it back to applescript HFS style path to use in the request to System Events and the script fails.

Are there other ideas for setting the property with the path so it can be used in the request to System Events?
I think there is more going on behind the scenes in the new environment that I don’t understand yet, because the property just doesn’t respond to applescript set commands I have tried after it is set by the IB Action in my posts above.

Jim

No, that should be:

set my theFile to lastPathComponent() of filepathControl’s |URL|()

Once again thanks Shane, that worked as well as my original call and gave me the same result, the file name, but your way is much cleaner.

The resulting path of the other part of the IB Action though, is still not useable in my script.
For: set filePath to |path|() of filepathControl’s |URL|() – file’s path
… I get a POSIX path like: /Users/username/Desktop/aFile.txt

Problem is that after a full day of googling and trying many variations on an attempt to convert this to a simple HFS style path (with colons) , the property in which the path resides seems to be locked, for lack of a better word. So when the script executes it halts at the command to get the value (and save it as alias, string, etc in another variable) that should convert it to a workable path in AS for use in the Tell statement above.

All conversion methods I have tried from getting the “POSIX file of” and setting another variable to it as a string, alias, etc have failed, so there is no reasonable expectation of using OBJ C generated POSIX paths in a practical way using Applescript to manipulate the file it points to. It will have to be done in Obj-C.
All I was doing was simple “Tell System Events” to get the modification date.

I did stumble on this article that implies almost the same situation existed in AS Studio from last year, where the users had to write a lot of conversion code just to get strings for the paths, although their usage of the paths were different than in my case… http://discussions.apple.com/thread.jspa?threadID=1398757&start=0&tstart=0

EDIT: Paragraph below contains false assumption- path controls do work - you may wish to skip this :smiley:
Until now my script was doing a lot of heavy lifting with these paths in only a few lines of code, which never took me more than a day to write. I know there needs to be a little pain in transitions such as this, but something as simple as paths in ASOC not working without converting my script to a cocoa application is far more effort/time than I can afford.
EDIT: Another rant you may wish to skip
I would love to be proven wrong here and shown a path pulled from a control in IB, saved in a property, then sending it to a Tell statement and returning file information to another property in 20 lines of code or less (My script does it in 4) , but unless I am missing something that is not possible in the new environment.
EDIT: Well, I was proven wrong. The above action also works in 4 lines (or less) in ASOC

All the best and thanks for your help and for this great forum.

Don’t despair!

Try something like this:

set filePath to |path|() of filepathControl's |URL|()
set hfsPath to (((filePath as text) as posix file) as text)

Well, like most biological units I have had to eat my words sometimes, but rarely so quickly after I had convinced myself of the absence of a workable solution to a problem. Forgive my hastiness in that conclusion. I have also marked up my previous post to ensure a healthy helping of those words were eaten.

Where are you getting these methods Shane? I can’t find a reference guide or documentation anywhere, even in the XCode documentation in the class methods etc, there is no indication to craft the applescript code to the structure you are using so fluently.

Thank you, thank you, thank you!

I tested in my app today and it is working very smoothly. I will add to this thread a working sample of the code you so graciously stepped me through to add path controls in the interface to my script, for others to benefit from.

I know there will probably more challenges to adding the remaining elements to the interface (another path control, a stepper, 3 text fields, a progress wheel), but none will be as challenging as this was, and I appreciate your guidance through it.

Now I have time to settle into this and learn the basics as I go along, thanks to your assistance and guidance.
Jim

The second line is pure AppleScript. It took me quite a while to work out too, because you’d normally say “posix file somePosixPath”, and that doesn’t work.

So you’re getting back a posix path, you have to coerce it to text because ObjC calls return pointers, you use AS’s “posix file” in a coercion, which returns an alias, and you then coerce that to text.

Say what? :rolleyes: Seriously, I didn’t know you were putting that amount of effort into it, it truly speaks to your dedication to us coders in moving us all forward.

OK as promised, here is my sample app to demonstrate what you have taught me, for the benefit of others who may come upon this thread.

Preparations: All that is needed for this to work after the IB outlets (properties) and the IB Action (handler) are saved in the script, is to go into IB and create a Path Control, and the only attribute I set was the Style attribute of popup. Also, I control dragged from the popup in the window, to the Test app delegate Blue Box, and selected the IB Action from the Received Actions list. Finally the third step was to Control Drag back from the App Delegate Blue Box to the control and select filepathControl as the Outlet. That’s all, took about 45 seconds. In the script I don’t know if I had to declare all the properties I was using, just did it to make sure all was well.

Expected Behaviour: Once Build and Run is selected, the user browses to and selects a file from the resultant dialog and selects the open button. The program will log to the console in debugger as well as present a dialog box to the user showing both the POSIX and the HFS paths of the file, as well as it’s name taken from the properties of the app and finally the modification date of the file. :slight_smile:
Another neat plum - if the control is set up as above i.e just change to the popup style was the only setting I used, the user can DRAG and DROP a file over the menu and that will select the file without a dialog and send the click action to the IB Action! very cool ! Drag and drop is supported in the default setup configuration of the pathcontrol.

Note that the exercise of actually getting the file’s modification date as mentioned in my previous posts only took 3 lines of code!, the first 3 of the IB Action, hence my excitement in actually doing it more efficiently than in my previous applescript, which was hard coded to the file and had no interface! But I had a little fun in writing to the log and playing with the dialog so wrote some extra lines for demonstration purposes.

Please jump in if there are any suggestions to improve the code and I will change it. Otherwise, I hope someone else can benefit as I did from Shane’s advice here.

script testAppDelegate
	property parent : class "NSObject"
	
	-- IB Outlets
	property filepathControl : missing value
	property thefilePath : missing value
	property hfsPath : missing value
	property theFilename : missing value
	property theText : missing value
	property modDate : missing value
	
	
	--IB Action
	on setPathInfoFromPopupPathControl_(sender)
		set thefilePath to |path|() of filepathControl's |URL|()
		set hfsPath to (((thefilePath as text) as POSIX file) as text)
		tell application "System Events" to set my modDate to modification date of alias (hfsPath)
		set my theFilename to lastPathComponent() of filepathControl's |URL|()
		log "The POSIX path is '" & thefilePath & "', the HFS path is '" & hfsPath & "' and the file name is " & theFilename & ", modified on " & modDate
		set theText to "The POSIX path is '" & thefilePath & "', the HFS path is '" & hfsPath & "' and the file name is " & theFilename & ", modified on " & modDate as string
		display dialog theText
	end setPathInfoFromPopupPathControl_
	
	
	on applicationWillFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened 
	end applicationWillFinishLaunching_
	
	
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return true
	end applicationShouldTerminate_
	
end script

This was a very worthwhile exercise for me. I learned a lot about one of the more difficult to code interface elements in ObjectiveC as well as ASOC. Thanks for your help Shane!

Enjoy!

This line of code


       set hfsPath to (((thefilePath as text) as POSIX file) as text)

literally saved me from going crazy. :stuck_out_tongue: Solved a problem I was trying to fix for the last 4 hours…

To all of you who end up here via google: If you get an error like “Can’t make «class ocid» id into type string/alias/text…” trying to access files for read/write access and tried converting Unix file paths to HFS file paths - This is the place to start looking for a fix.

The coercing of data back and forth is taking a while to get used to.

Thank you very very much!!

Best regards,

Oliver

Note: As thefilePath is anyway NSString (text) this gets rid of two coercions


       set hfsPath to (POSIX file thefilePath) as text

True, thanks for the hint.

Except it doesn’t work if thefilePath is the result of an ObjC method, which is really the whole point of the exercise. The returned result has to be coerced to text before it can be used with “POSIX file”, otherwise you get an error:

		set thefilePath to |path|() of filepathControl's |URL|()
		set hfsPath to (POSIX file thefilePath) as text
		--> Can't make «class ocid» id «data kptr00000000F0D47170FF7F0000» into type «class psxf». (error -1700)

It’s also worth noting that this will also fail:

		set hfsPath to ((POSIX file (thefilePath as text)) as text)
            --> Can't make «script» into type text. (error -1700)

For some reason, forms like “POSIX file x” and “alias y” often have to be rewritten as “x as POSIX file” and “y as alias” in ASObjC.

Thanks for the explanation.
In classic AppleScript Studio NSString and class text were interchangable.
I think I will keep out of this AppleScriptObjC business at the moment.
I’m not sure whether it’s more blessing or more curse :wink:

They are, more or less, in ASObjC too, except that they get returned as a kind of pointer.

THANK YOU for this Shane! Helped me a ton. :slight_smile: