I have a document, and it does undo with its undo manager.
The menu item undo, with its key command cmd-Z, is by default connected in IB to First Responder with selector “undo:”.
So far all is good and works well.
The user can open a utility panel, which can do things in the document.
While the utility window is ‘Key’, I want the undo to still work, so that when something has been done to the document from the utility panel, a press of cmd-Z will undo the action. Very obvious.
Trouble is that the undo command is grayed out when the utility panel is ‘Key’!?
The document window is still ‘Main’ though.
I just don’t understand how to get the responder chain to look for the undo in the right place, i.e the undo manager of the document?
I’ve tried things with setNextResponder, and also delegate stuff, but I am obviously doing it wrong.
(I do note that the action of the undo menu command is “undo:”, i.e with one parameter, whereas the undo method of NSUndoManager is “undo”, i.e no parameter. Hmm. it makes me a bit confused as to how the responder chain actually handles that.)
Does the panel belong to a document?
Now you are saying something that probably is very crucial to my lack of understanding of this problem…
The panel belongs to the same nib as the document’s window, and this nib is owned by the document class (the “File’s Owner”). The panel is opened from the toolbar of the window that shows the document. But I haven’t done anything else to make it “belong to the document” any more than that.
OK, that sounds fine. The next question is how are you making the changes to the document, and to what. A lot of changes are not automatically recorded by the undo manager.
I call a method of the document (in my case setValues_forKey_atRows_(…)) which does all that complex undoManager thang. That method is coded in ASOC, whereas the code for the panel that calls this method is coded in pure ObjC, but that is probably irrelevent.
The undo manager properly gets registered with this, so it works perfectly. If I make the main window the Key, then I can undo arbitrarily much, so the coding works fine. The only problem is that as long as the panel is Key, the undo command is unavailable.
Ok, I finally found a way to make it work. I am open to opinions though – maybe there is a more elegant, general or “proper” way to do it.
As I suspected, the problem is the responder chain.
In my first attempts to explicitly set the next responder, I did that in the init method in the ObjC file that was supposed to handle things. That is obviously not the right place to set the next responder of the panel.
But if I set the next responder in the ASOC file that opens the panel, then it all works!
So, the short code that opens the panel is like the following (which thus runs inside the NSDocument subclass):
controlPanel's makeKeyAndOrderFront_(missing value)
(the windowForSheet is just a quick way to get the window of the document)
But one can always ask if this way of explicitly setting the next responder is a crutch or the recommended solution to similar things.
it looks like a reasonable approach to me.