Cocoa: Forward actions (copy:, paste: etc.) up to

2019-07-13 02:05发布

问题:

I have a subclass of NSOutlineView that implements copy:, paste:, cut: etc. Also, the NSDocument subclass implements these same methods.

When the outline view is in the responder chain (is first responder or a parent view of it), all copy/paste events are intercepted by the NSOutlineView subclass. What I want, is depending on the context catch some of these messages, or let them propagate and be caught by the NSDocument subclass.

What I want is basically:

- (void)copy:(id)sender
{
    // If copy paste is enabled
    if ([self isCopyPasteEnabled]) {
        [[NSPasteboard generalPasteboard] clearContents];
        [[NSPasteboard generalPasteboard] writeObjects:self.selectedItems];
        return;
    }

    // If copy paste is disabled
    // ... forward copy: message to the next responder,
    // up to the NSDocument or whatever
}

I've already tried many tricks, none was successful:

  • [[self nextResponder] copy:sender] that doesn't work because the next responder may not implement copy:
  • [super copy:sender] same here, super doesn't implement copy:
  • [NSApp sendAction:anAction to:nil from:sender] this is nice to send an action to the first responder. If used inside an action

Sure I could manually loop on the responder chain until I find something that responds to copy: or even directly call copy: on the current document, but I'm looking for the right way of doing it.

Many thanks in advance!

回答1:

This should work:

[[self nextResponder] tryToPerform:_cmd with:sender];

There's a problem, though: the presence of a responder in the responder chain which implements -copy: will, in and of itself, cause the Copy menu item to be enabled even if it wouldn't otherwise be if your object weren't in the chain or didn't implement -copy:. Your object could disable that item using -validateMenuItem: or -validateUserInterfaceItem:, but it will be nontrivial to enable if and only if there's another potential target up the chain and that target would enable the item.

A different approach is to just make the search for a responder that implements the action method skip your outline view if you disable pasteboard support. Override -respondsToSelector:. If the selector is one of the pasteboard operations and your pasteboard support is disabled, return false even though your class really does implement it. That is, lie and claim your object just doesn't respond to those selectors. For any other selector, or if your pasteboard support is on, call through to super and return what it returns.