Re: How to run a panel that customizes a new NSDocument
Re: How to run a panel that customizes a new NSDocument
- Subject: Re: How to run a panel that customizes a new NSDocument
- From: Ben Haller <email@hidden>
- Date: Wed, 21 Oct 2009 21:38:39 -0400
On 21-Oct-09, at 7:23 PM, Quincey Morris wrote:
On Oct 21, 2009, at 15:55, Ben Haller wrote:
OK, I've switched over to an NSDocumentController and using
different types for my different models. That turned out to be a
forced move, because NSApplication's delegate method -
applicationOpenUntitledFile: does not get called when the user
chooses New from the File menu; that seems to go right to
NSDocumentController. -applicationOpenUntitledFile: only seems to
get called for the new document created when an app is launched or
brought front without an open document. I could have started
changing the actions for menu items and so forth, but I decided
that since my app is document-based, I ought to go with the
document architecture. So I now have an NSDocumentController
subclass, and I override openUntitledDocumentAndDisplay:error:.
That seems to be in the code path for all kinds of new documents.
However, I still find this architecture quite unsatisfying. My -
openUntitledDocumentAndDisplay:error: subclass still needs to do
way too much work:
- (id)openUntitledDocumentAndDisplay:(BOOL)displayDocument error:
(NSError **)outError
{
[...]
}
The sequence of -makeUntitledDocumentOfType:error:, then
makeWindowControllers, then showWindows, is already in super, but I
don't have any way to make super do it. So I have to duplicate
that sequence in my own code, which makes my code vulnerable to
architectural changes in NSDocument. I gather this sequence has
already changed at least once in the past, so it is clearly fragile.
There really must be a better way to do this; I feel like I'm
running at counter purposes to the design of the framework. Anyone
have any better suggestions?
I'm curious as to why -makeUntitledDocumentOfType:error: doesn't do
the work of adding the document, setting up its windowController,s
and showing the windows. That would seem like the natural design
to me, rather than making everyone that calls that method do that
work themselves. Is there a reason for this design?
I don't understand why you think you can't invoke [super
openUntitledDocumentAndDisplay: displayDocument error: outError]
immediately after displaying your initial-state-choosing dialog.
Because of the need to pass a customized type string? In that case,
stash the type in a subclass instance variable and override
defaultType to return it. Alternately, put the initial state in a
global variable and consult that variable in your NSDocument
subclass initWithType: -- that's a bit ugly, but it's safe enough
because this all needs to be done on the main thread anyway.
Both of those options seem more than a little bit ugly to me. They
depend quite intimately on the behavior of the NSDocument
architecture, and the ordering of events. If, for example,
NSDocumentController decided to make a different new document in the
middle of this process, for whatever reason (and processing multiple
documents for opening or printing makes that seem not implausible),
both of these workarounds could backfire.
Clicking cancel in my "choose a model" window returns a nil string
to my NSDocumentController subclass -
openUntitledDocumentAndDisplay:error:, and I see that nil and
immediately return nil myself, since the user has cancelled. That
results in a raise from the Kit:
If you're using the code you posted earlier (snipped out above),
then you're not returning an error object when you return nil at the
end of the method.
Well, two points in response to that. One, the NSError
documentation says:
In general, a method should signal an error condition by—for example—
returning NO or nil rather than by the simple presence of an error
object. The method can then optionally return an NSError object by
reference, in order to further describe the error.
So if the NSError is required, that seems questionable.
More importantly, however, if I do make an NSError object and pass
it back, then the NSDocument architecture displays an error panel to
the user that says "No document could be created"! Since the user has
just clicked Cancel, that is obviously wrong. If I select New in
Interface Builder, then cancel out of it, I don't get a panel warning
me that a new document could not be created.
Is anybody at Apple reading this thread? I'd really like to get
advice from somebody who knows how this architecture was intended to
be used. I can't imagine that such a simple, common usage pattern
falls through cracks in the design. I must simply be using the
framework incorrectly. Anyone who has actually implemented a document
like this care to comment?
Ben Haller
Stick Software
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden