Have you noticed how TextEdit or TextMate will open an existing file in the “Untitled” window, if it is empty? I thought this was a default behaviour of the multi-document architecture of AppKit. While writing multi-document support for ImageFramer 3 (ImageFramer 2 is a single-document application) I noticed that it always opens a document in a new window, even if I have not touched the default empty document.

After some research I’ve found the following facts:

  • NSDocumentController always opens documents in a new window by default
  • TextEdit uses a lot of custom code to manage this behavior. TextEdit is an open sourced examples which is installed with Xcode, at /Developer/Examples/TextEdit/. I didn’t want such a complicated solution for myself.

I ended up implementing my own solution for my case. It might not suit your needs but could help choose the correct path for you.

My solution maybe unique to me since ImageFramer’s document are images and not some custom format. In ImageFramer version 3 I’ll be saving the framing designs in Core Data inside the application, so they’re not regular documents by default.

I have a method in my NSDocument subclass that loads the image into the already existing document. So the image is not read in - (BOOL)readFromURL:ofType:error: but rather at a later stage, in - (void)windowControllerDidLoadNib: (NSWindowController *)aController method. There I check [self fileURL]. If it’s not nil, then I import the image into the document. If it’s nil, I load the default one and it becomes the “Untitled” document.

So what did I do to open images in the same window instead of the default one? I had to make changes in 2 classes:

1. In my NSDocument subclass I setup a method isDefaultImage which does what its name implies. I then set it to YES if I load the default image file. In general case you could name it
- (BOOL)isReplaceableDocument and handle all logic there. For example, you might want to return NO here if user has modified the document and you don’t want him to loose his changes.

2. In NSDocumentController subclass, I overloaded openDocumentWithContentsOfURL:display:error:. Here’s the whole method:

- (id)openDocumentWithContentsOfURL:(NSURL *)absoluteURL display:(BOOL)displayDocument error:(NSError **)outError
    if (![[self currentDocument] isDefaultImage])
        return [super openDocumentWithContentsOfURL:absoluteURL display:displayDocument error:outError];
    else {
        [[self currentDocument] importImage:absoluteURL];
        [[self currentDocument] setFileURL:absoluteURL];
        return [self currentDocument];

So, if I can’t replace to document, I just call super and return its result. If I can replace, I ask the current document to import the image, replacing my placeholder image. Then I set document’s URL to the provided one, so that it won’t stay as Untitled and will place the icon on the titlebar of the window.

That’s all.

Granted, in TextEdit example they take a more complex path, which probably may be better for them. From what I gathered, they create a new document manually and then copy the window controller from the Untitled document (they call it transient) to the new document. There’s more code there and you probably should take a look there to see if it suits you better.

Pin It on Pinterest

Share This