Nsdocumentcontroller.Opendocument Not Allowing Selection of Custom File Type

NSDocumentController.openDocument not allowing selection of custom file type

Your UTExportedTypeDeclarations entry is missing UTTypeConformsTo. This key is required. See Uniform Type Identifier Concepts - Conformance and Declaring New Uniform Type Identifiers.

Although a custom UTI can conform to any UTI, public.data or com.apple.package must be at the root of the conformance hierarchy for all custom UTIs that are file formats (such as documents);

Also:

You need to declare conformance only with your type’s immediate “superclass,” because the conformance hierarchy allows for inheritance between identifiers. That is, if you declare your identifier as conforming to the public.tiff identifier, it automatically conforms to identifiers higher up in the hierarchy, such as public.image and public.data.

System-Declared Uniform Type Identifiers

<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>ccutibug document</string>
<key>UTTypeIdentifier</key>
<string>com.mathaesthetics.ccutibug</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>asdfg</string>
</array>
</dict>
</dict>
</array>

I also removed com.apple.ostype, which was used in classic Mac OS and is not required for new file types.

And match public.filename-extension and CFBundleTypeExtensions:

<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>asdfg</string>
</array>
<key>CFBundleTypeIconFile</key>
<string></string>
<key>CFBundleTypeName</key>
<string>ccutibug document</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSItemContentTypes</key>
<array>
<string>com.mathaesthetics.ccutibug</string>
</array>
<key>LSTypeIsPackage</key>
<false/>
<key>NSDocumentClass</key>
<string>$(PRODUCT_MODULE_NAME).CCDocument</string>
</dict>
</array>

Note: I also changed <integer>0</integer> to <false/> to make it more readable.

Debugging

During development changing the UTI can confuse the LaunchServices database. You can try to reset it by running:

/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister
-kill -r -domain local -domain system -domain user

Note: Make sure that you don't have any old dev build on your system, like in the Xcode Build Folder or Xcode Product Archives. These could continue to confuse the LaunchServices database

The -dump option is helpful to see current UTI declarations:

/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister
-dump

Open any folder with NSDocument

You probably can't do this without writing some custom code.

You need to present an NSOpenPanel manually, like this:

NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setCanChooseFiles:NO];
[panel setCanChooseDirectories:YES];

[panel beginSheetForDirectory:nil
file:nil
modalForWindow:[self window]
modalDelegate:self
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
contextInfo:nil];

An open panel presented in this way will let the use choose any directory they wish. You can implement NSOpenPanel's delegate methods to validate each folder and en/disable if if you need to.

After changing Document Parameters, NSCocoaErrorDomain 256 opening *new* docs

Apparently the problem is in updating the Launch Services database. I copied the new application, with the revised Info.plist, into /Applications, replacing an old version, then launched this copy once. After these two steps, document icons are now correct when I reopened a Finder window, and upon relaunching my new app, it can now reopen its own new documents without error.

UPDATE: Today (macOS 10.13 Beta 8) I had the same problem, but installing the corrected app into /Applications did not work. However, this time, rebuilding the Launch Services database by running the following command in Terminal, and then relaunching my app, did work:

/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain u -domain s -domain l -v

A side effect of the above is that some apps will have generic icons in the dock and cmd-tab application switcher until relaunched.

I think that either Launch Services much prefers apps in /Applications over apps in Xcode's DerivedData folder, even if the latter is the only one currently running, or running apps from Xcode's DerivedData do not register at all, or both.

It seems from the documentation that calling LSRegisterURL() should have had the same effect, but apparently not.

Document based OSX app - Limit number of open documents to one

It won't be an easy solution, since it's a pretty complex class, but I would suggest that you subclass NSDocumentController and register your own which disables opening beyond a certain number of documents. This will allow you to prevent things like opening files by dropping them on the application's icon in the dock or opening in the finder, both of which bypass the Open menu item.

You will still need to override the GUI/menu activation code to prevent Open... from being available when you have a document open already, but that's just to make sure you don't confuse the user.

Your document controller needs to be created before any other document controllers, but that's easy to do by placing a DocumentController instance in your MainMenu.xib and making sure the class is set to your subclass. (This will cause it to call -sharedDocumentController, which will create an instance of yours.)

In your document controller, then, you will need to override:

- makeDocumentForURL:withContentsOfURL:ofType:error:
- makeUntitledDocumentOfType:error:
- makeDocumentWithContentsOfURL:ofType:error:

to check and see if a document is already open and return nil, setting the error pointer to a newly created error that shows an appropriate message (NSLocalizedDescriptionKey).

That should take care of cases of drag-and-drop, applescript,etc.

EDIT
As for your additional request of the close/save prompt on an opening event, that's a nastier problem. You could:

  1. Save off the information (basically the arguments for the make requests)
  2. Send the -closeAllDocumentsWithDelegate:didCloseAllSelector:contextInfo: with self as a delegate and a newly-created routine as the selector
  3. When you receive the selector, then either clear out the saved arguments, or re-execute the commands with the arguments you saved.

Note that step 2 and 3 might need to be done on delay with performSelector

I haven't tried this myself (the rest I've done before), but it seems like it should work.

Problem registering file type through UTIs

You also need a CFBundleDocumentTypes declaration.

<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeIconFile</key>
<string>MyAppLicenseIcon</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>NSDocumentClass</key>
<string>MyAppLicenseHandler</string>
<key>LSItemContentTypes</key>
<array>
<string>com.mycompany.myapplicense</string>
</array>
</dict>
</array>


Related Topics



Leave a reply



Submit