Page 1 of 1
Re: [Cocoa] Extra file operations
Posted: Fri Jul 17, 2015 5:31 pm
by Shardik
kenmo wrote:(b) display the "Get Info" window about a file
This code example displays the "Get Info" window for a specified file (successfully tested with Snow Leopard and Yosemite):
Code: Select all
EnableExplicit
ImportC ""
NSPerformService(*ItemName, *NSPasteboard)
EndImport
Define Pasteboard.I
Define TargetFile.S = #PB_Compiler_Home + "logo.png"
Define TypeArray.I
; ----- Create Pasteboard
Pasteboard = CocoaMessage(0, 0, "NSPasteboard pasteboardWithUniqueName")
If Pasteboard
TypeArray = CocoaMessage(0, 0,
"NSArray arrayWithObject:$", @"NSStringPboardType")
If TypeArray
CocoaMessage(0, Pasteboard,
"declareTypes:", TypeArray,
"owner:", 0)
If CocoaMessage(0, Pasteboard,
"setString:$", @TargetFile,
"forType:$", @"NSStringPboardType") = #YES
; ----- Show info for selected file
NSPerformService(CocoaMessage(0, 0,
"NSString stringWithString:$", @"Finder/Show Info"), Pasteboard)
EndIf
EndIf
EndIf
If you also need to open the Finder with the specified file selected you may try the following extended code:
Code: Select all
EnableExplicit
ImportC ""
NSPerformService(*ItemName, *NSPasteboard)
EndImport
Define Pasteboard.I
Define TargetFile.S = #PB_Compiler_Home + "logo.png"
Define TypeArray.I
Define Workspace.I = CocoaMessage(0, 0, "NSWorkspace sharedWorkspace")
If Workspace
; ----- Open Finder and select target file
CocoaMessage(0, Workspace,
"selectFile:$", @TargetFile,
"inFileViewerRootedAtPath:$", @"")
; ----- Create Pasteboard
Pasteboard = CocoaMessage(0, 0, "NSPasteboard pasteboardWithUniqueName")
If Pasteboard
TypeArray = CocoaMessage(0, 0,
"NSArray arrayWithObject:$", @"NSStringPboardType")
If TypeArray
CocoaMessage(0, Pasteboard,
"declareTypes:", TypeArray,
"owner:", 0)
If CocoaMessage(0, Pasteboard,
"setString:$", @TargetFile,
"forType:$", @"NSStringPboardType") = #YES
; ----- Show info for selected file
NSPerformService(CocoaMessage(0, 0,
"NSString stringWithString:$", @"Finder/Show Info"), Pasteboard)
EndIf
EndIf
EndIf
EndIf
Re: [Cocoa] Extra file operations
Posted: Fri Jul 17, 2015 5:57 pm
by Shardik
WilliamL wrote:Ok, it works perfectly except after moving the file to the trash, and sucessfully saving the new file, I get back to the 'WaitWindowEvent()' and I get an 'Invalid Memory Access' error. [later] ok, if I take out 'CocoaMessage(0, TrashFileURL, "release")' I don't get the error message. Is this action necessary?
William, you are right. Wilbert has sent me a PM with following explanations for mistakes in my code from above (Wilbert, again thank you very much, you are simply the best mentor I can imagine!):
wilbert wrote:A few remarks about your code example ...
Return objects like resultingItemURL and error should not be allocated nor released.
The method itself allocates them and they are autoreleased.
For objects you create yourself, in general those created with alloc or new need to be released manually and other ones are autoreleased.
The object created by NSURL fileURLWithPath therefore is an autorelease object so you should not release it manually otherwise it might result in a crash.
For other readers of this thread I therefore decided against editing my above code example but to post here the modified version with the changes proposed by Wilbert so that others may also learn from my mistakes:
Code: Select all
EnableExplicit
Define Error.I
Define Result.I
Define TestFile.S = GetTemporaryDirectory() + "Test.Txt"
Define TestFileURL.I
Define TrashFileURL.I
If OSVersion() < #PB_OS_MacOSX_10_8
MessageRequester("Error",
"Sorry, but this program needs at least Mountain Lion!")
End
EndIf
If CreateFile(0, TestFile)
WriteString(0, "This file should be moved to the trash can!")
CloseFile(0)
TestFileURL = CocoaMessage(0, 0,
"NSURL fileURLWithPath:$", @TestFile,
"isDirectory:", #NO)
If TestFileURL
Result = CocoaMessage(0, CocoaMessage(0, 0, "NSFileManager defaultManager"),
"trashItemAtURL:", TestFileURL,
"resultingItemURL:", @TrashFileURL,
"error:", @Error)
If Result = #YES
MessageRequester("Success", "The file '" + GetFilePart(TestFile) +
"'" + #CR$ + "was successfully moved to trash as file" + #CR$ + "'" +
PeekS(CocoaMessage(0, CocoaMessage(0, TrashFileURL,
"lastPathComponent"), "UTF8String"), -1, #PB_UTF8) + "'")
Else
MessageRequester("Error", "Moving file " + GetFilePart(TestFile) +
" to trash has failed!" + #CR$ + #CR$ + PeekS(CocoaMessage(0,
CocoaMessage(0, Error, "localizedDescription"), "UTF8String"),
-1, #PB_UTF8))
EndIf
EndIf
EndIf
Re: [Cocoa] Extra file operations
Posted: Fri Jul 17, 2015 6:14 pm
by WilliamL
Thanks Shardik for the new code it works perfectly.
I appreciate Wilbert's and your efforts to understand Cocoa and it is a
great addition to the PB forum. I can't thank you both enough and I'm sure there are many others that feel the same way.

Re: [Cocoa] Extra file operations
Posted: Fri Jul 17, 2015 9:20 pm
by kenmo
Lots of great information here, thank you! I will try it out as soon as possible.
Re: [Cocoa] Extra file operations
Posted: Sat Jul 18, 2015 10:58 am
by Shardik
Here is another code example to move a file to trash that utilizes the
NSWorkspace method
recycleURLs:completionHandler: proposed by Wilbert. It works with MacOS versions beginning with Snow Leopard and I have tested it successfully on Snow Leopard and Yosemite:
Code: Select all
EnableExplicit
Define FileArray.I
Define TestFile.S = GetTemporaryDirectory() + "Test.Txt"
Define TestFileURL.I
Define Workspace.I = CocoaMessage(0, 0, "NSWorkspace sharedWorkspace")
If OSVersion() < #PB_OS_MacOSX_10_6
MessageRequester("Error",
"Sorry, but this program needs at least Snow Leopard!")
End
EndIf
If Workspace
If CreateFile(0, TestFile)
WriteString(0, "This file should be moved to the trash can!")
CloseFile(0)
; ----- Create URL from TestFile string
TestFileURL = CocoaMessage(0, 0,
"NSURL fileURLWithPath:$", @TestFile,
"isDirectory:", #NO)
If TestFileURL
; ----- Create Array of URLs using TestFileURL (only 1 element)
FileArray = CocoaMessage(0, 0, "NSMutableArray arrayWithCapacity:", 1)
CocoaMessage(0, FileArray, "addObject:", TestFileURL)
If FileArray
; ----- Move the URLs to the trash in the same manner as in the Finder
CocoaMessage(0, Workspace,
"recycleURLs:", FileArray,
"completionHandler:", 0)
MessageRequester("Info", "The file '" + TestFile + "'" + #CR$ +
"was successfully moved to trash!")
EndIf
EndIf
EndIf
EndIf
Re: [Cocoa] Extra file operations
Posted: Wed Jul 22, 2015 2:46 am
by kenmo
Shardik, is it "safe" to package your Get Info code in a procedure like this?
Do any of these objects need to be freed? Is it bad to call these repeatedly (I'm not sure what a "pasteboard" is yet)...
Code: Select all
Procedure GetInfo(File.s)
Protected Pasteboard.i = CocoaMessage(0, 0, "NSPasteboard pasteboardWithUniqueName")
If (Pasteboard)
Protected TypeArray.i = CocoaMessage(0, 0, "NSArray arrayWithObject:$", @"NSStringPboardType")
If (TypeArray)
CocoaMessage(0, Pasteboard, "declareTypes:", TypeArray, "owner:", 0)
If (CocoaMessage(0, Pasteboard, "setString:$", @File, "forType:$", @"NSStringPboardType") = #YES)
NSPerformService(CocoaMessage(0, 0, "NSString stringWithString:$", @"Finder/Show Info"), Pasteboard)
EndIf
EndIf
EndIf
EndProcedure
Re: [Cocoa] Extra file operations
Posted: Thu Jul 23, 2015 8:22 pm
by Shardik
kenmo wrote:Shardik, is it "safe" to package your Get Info code in a procedure like this?
Do any of these objects need to be freed? Is it bad to call these repeatedly (I'm not sure what a "pasteboard" is yet)...
At first you still have to import
NSPerformService() for your procedure GetInfo(File.s) to work:
Code: Select all
ImportC ""
NSPerformService(*ItemName, *NSPasteboard)
EndImport
An NSPasteboard is a clipboard. I assume that PureBasic on MacOS X is wrapping NSPasteboard methods for its native clipboard commands. But PureBasic's clipboard is a public clipboard whereas the Cocoa method
pasteboardWithUniqueName will create a unique clipboard which won't interfere with the contents of other clipboards. This unique clipboard will be closed automatically when your program ends, so in order to not create a new unique clipboard with each call of your procedure I would use Static to create this clipboard together with the TypeArray only once in your procedure:
Code: Select all
ImportC ""
NSPerformService(*ItemName, *NSPasteboard)
EndImport
Procedure GetInfo(File.s)
Static Pasteboard.i
Protected TypeArray.i
If Pasteboard = 0
Pasteboard = CocoaMessage(0, 0, "NSPasteboard pasteboardWithUniqueName")
If Pasteboard
TypeArray.i = CocoaMessage(0, 0,
"NSArray arrayWithObject:$", @"NSStringPboardType")
If TypeArray
CocoaMessage(0, Pasteboard, "declareTypes:", TypeArray, "owner:", 0)
EndIf
EndIf
EndIf
If CocoaMessage(0, Pasteboard,
"setString:$", @File,
"forType:$", @"NSStringPboardType") = #YES
NSPerformService(CocoaMessage(0, 0,
"NSString stringWithString:$", @"Finder/Show Info"), Pasteboard)
EndIf
EndProcedure
Re: [Cocoa] Extra file operations
Posted: Thu Jul 23, 2015 11:38 pm
by kenmo
Thanks for the additional information! I will use one static Pasteboard pointer, and I can leave TypeArray as a Protected.
Shardik wrote:At first you still have to import NSPerformService() for your procedure GetInfo(File.s) to work:
Of course. I also like to wrap them in compiler safeguards, so that multiple snippets in the same project can import the same API function without PB compilation errors.
Code: Select all
ImportC ""
CompilerIf (Not Defined(NSPerformService, #PB_Procedure))
NSPerformService(*ItemName, *NSPasteboard)
CompilerEndif
EndImport