My app uses folders as if they were files: a folder is a container for multiple file types. It’s handy, but I think that my “Open” and “Save” dialogs will be a bit confusing for my users.
If you have an Open dialog filtering folders, when you double-click on a folder it does not open this folder into the application, but indeed opens the folder into the dialog window, with all contained files disabled. You have to click on the “Choose” button. Same thing when you double click on a desktop’s folder: it opens, and does not launch my app. Not good.
I want my folders to disguise in files, to be filtered like files, to open like files when you double-click on them.
I read about the NSFileWrapper class, but as usual it’s not just «set the wrapper bit of the folder to transform it into a wrapper». It seems to be complicated (and of course it’s probably “very simple indeed” if you are used to do this).
Question: how can I, with minimal change of code, transform my folders into wrappers? I want to keep the folders contents as they are, just transform the folder into a (file? directory?) wrapper. Is it possible, or do I have to change all my app’s design?
You need to declare your file type as a package in the target properties. Then to save a package you can just create an empty file wrapper, write it, then write the contents to it as if it’s just a folder. Something like:
set aWrapper to current application's NSFileWrapper's alloc()'s initDirectoryWithFileWrappers_(missing value)
tell aWrapper to writeToFile_options_originalContentsURL_error_(theURL, current application's NSFileWrapperWritingAtomic, missing value, missing value)
In XCode 3.x, there was a check box to mark a document as package. Where is it in XCode 4? I can’t find it.
what about the “Open” and “Save” dialogs (I’m using AS’s Choose folder, not your helpers, but this can be changed)
is it possible to limit the dialog’s display to my package “file extension” as if it was a file?
in my app, I use the NSFileManager (pretty handy class!) to make my folder the default one, so I don’t have to specify a complete path, only the file name. Can I do the same with a wrapper/package?
Can I, for debug, open my package with right-click, as with TextEdit’s RTFD or application packages?
/*
NSPersistentDocument’s implementation is bypassed using the FileWrapperSupport category. The persistent
store coordinator is directed to use an internal URL rather than NSPersistentDocument’s default (the main file URL).
*/
Do I have to import FileWrapperSupport.h explicitly or is it included into the frameworks?
My files were saved with the class NSPersistentDocument. Do I have to change this?
Option 3 (because of unnecessarily complication of Cocoa): leaving things as they are and add to my application’s documentation a clause like “For God’s sake, do NOT modify the folder contents”.
Reminder: the former version of my app was dealing with indexed resources in one single file.
Oh, I don’t know what I’m using, in fact. When I defined my docs types, “Persistent document” seemed a logical choice, that’s all, I didn’t look further – and my files were persistent, so I let this option on.
If I read the doc correctly, a file wrapper is a kind of, or retains somewhere, a dictionary which contains the relative path (URL) of its files. So I’m not sure it can’t be so simple. The code you proposed to me gives this error:
Indeed I found no method with this name. There is a:
“ writeToURL:options:originalContentsURL:error:
and a:
“ writeToFile:atomically:updateFilenames: Deprecated in Mac OS X v10.6
when I send writeToURL with POSIX path of returnedFolder as first parameter (and a posix file is equivalent to an URL, right?) I get:
Persistent documents are for core data only. If you’re ding all your own saving and opening, you may not need anything other than NSObject anyway – the point of using NSDocument is to get all the open/save/revert/etc behavior for free.
That’s the one.
Wrong. A path and a URL are different. Back to the book …
on testCreatePackage_(sender)
set sp to current application's NSSavePanel's savePanel()
sp's runModal()
set aWrapper to current application's NSFileWrapper's alloc()'s initDirectoryWithFileWrappers_(missing value)
tell aWrapper to writeToURL_options_originalContentsURL_error_(sp's |URL|(), current application's NSFileWrapperWritingAtomic, missing value, missing value)
end
creates a normal folder. Well, it’s already better.
The problem is, I don’t see where, in these calls, the NSFileWrapper guesses what is the file extension.
As well as what leonsimard says, your UTI exporting could do with some work. I don’t know why it’s in twice. Try something like this, putting in the correct bundle identifier:
What is the purpose for exporting the UTI? Is this an alternative to setting a file extension and clicking the package box in the target info pane? That worked fine for me – is there something else that exporting the UTI does for you?
Is there a way, with or without file wrappers, to have an open panel that only shows files with a particular extension – and by shows, I mean that’s all it shows, not grayed out files of other types or folders?
Am I right in thinking that there are two ways to save files in a directory file wrapper – one, by using addRegularFileWithContents_preferredFilename_ to add files to the file wrapper and then writing out the file wrapper to disc? And two, by writing out an empty directory file wrapper to disc and then saving files to it as if it were a regular folder?
To let other apps, like the Finder, know about the file type. Presumably it’s used/stored by launchd. It’s also a way of staking a claim to ownership of the filetype and extension.
No, it’s something you should do as well. See the doc “Declaring New Uniform Type Identifiers”.
I don’t think so. I suspect that falls into the category of subverting the HIG, so you’re going to have to fight the frameworks (or build your own dialog).
I have a feeling that using initRegularFileWithContents: and initDirectoryWithFileWrappers: is a third method. I’ve been using the wrapper-first method with no problems.
But why? Is it just good programming practice, or does it do something else that I don’t get by setting a document type, file extension and whether the file is package or not – when I do that, I get the correct extension and my app is the default opener of that type of file. So, if I’m not looking to share my data with other apps or have it somehow publicly available is there a need to do it?
As far as the document, it’s pretty much completely non-informative. It gives one example with no instructions, so I have no Idea how to write my own. I don’t even know the process – do you write that all manually yourself? It looks like I would have to learn XML to do that. When I look at the code you posted above and the example code in the docs, I see some similarities and some differences – so, I don’t know what is necessary in these declarations and I don’t see anything in the docs that teaches me how to do this.
Exporting a UTI makes it the definitive word on how files with that extension are treated. It also lets you add extra stuff like conformance and pasteboard types, should they apply to your docs. You can probably get away without it, but I’m not sure why you wouldn’t want to give the system the info it wants in the form it wants it.
You can write it by using the example in the docs as a template. There’s also a form for it in Xcode 4, although they seem to have left out the Package checkbox.
On a more pragmatic level, I got a log message when I made a mistake in one recently, so maybe it’s a useful way to check ow you’ve set up document UTIs.