Sunday, November 15, 2009

NSDocumentController - Maintaining a single document

I have been trying to figure out the best way to structure things to support the concept of the "main frame". Under Windows applications generally seem to have a main frame. This is the single key window that is central to the application. The OSX world is different - you generally have multiple windows one for each document. As a Mac user, now working windows much of the time. I find the paradigm a little strange at first. That said once you are accustomed it is fine. Also as I have mentioned before it is something that you see in some consumer apps on OSX so I am keeping this behaviour.

The trick with these things is, as ever, to find the path of least resistance. Now that I am working with Cocoa I want to do the same on the Cocoa end. I don't want to fight AppKit I want to dovetail in as well as I can so that I have to do as little as possible.

Looking at AppKit I definitely want to retain an NSDocument. I want this as NSDocument hooks into the undo manager really nicely. I will have to somehow mesh Cello's undo manager with NSDocument but that is something that I will look at later. The NSDocument as support for all the open and saving and I can hook into this.

So what I have done is write my own subclass of NSDocumentController - this is the master controller for all of my documents (the thing is I only ever have one). So my sub class will ensure that there is just one document - so if you open a document it will close the existing one.

I started by adding two methods to my document controller

- (void)addDocument:(NSDocument *)document {
[super addDocument:document];
}

- (void)removeDocument:(NSDocument *)document {
[super removeDocument:document];
}

So I could add breakpoints to check where these things were called. I could add breakpoints using GDB to the NSDocumentController methods - but I like this way. I wrote a new method that closeAllDocuments to close all of the documents (there should only ever be one). And then call that at appropriate times.
  • - (IBAction)newDocument:(id)sender
  • - (IBAction)openDocument:(id)sender
Finally I made my document controller my application delegate (if I need to I can always change this) so that I could implement the two methods:
  • - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename
  • - (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
And that takes care of the best part of it.

While figuring this out I came accoss the following post that proved very usefull here. The post is in Japanese which I was not able to follow - but the code was usefull.

No comments: