Get Notified when NSMenu removes all items - cocoa

I need to get notified when menu items in an NSMenu instance get removed. Specifically because I'm holding a NSMenuItem *selectedItem instance in my class. If this selectedItem gets removed from my NSMenu instance, i want to set the selectedItem to nil;
There is a notification for NSMenu called "NSMenuDidRemoveItemNotification" that works when you remove individual items from the menu. But when you call [myNSMenu removeAllItems] it does not get called.
Any ideas? , Do I need to subclass NSMenu ?
Thanks.

Yes, you are right, there is no notification for removeAll.
And you rightly said you need to subclass
Or, need some tricks (may be hacky work)
Even you can make a category with a method as removeEachItem.
If the menu is left with only one item you can track that NSMenuDidRemoveItemNotification is getting called last time, you are done with your requirement.

Related

validateMenuItem on NSViewController

Is it possible to have validateMenuItem work with NSViewControllers? The docs say NSViewController is a subclass of NSResponder so I would think it would participate in the responder chain, but I have never been able to get it to work. I can make it work with NSView, no problem.
The particular use case I have is a menu item in the MainMenu.xib, connected to First Responder. The selector from my view controller subclass shows up in the First Responder pop up list of selectors in MainMenu, so I would think it would work, but it doesn't. The validateMenuItem method of my subclass is never called. (The one in the app delegate is called, but not for the item which is connected to First Responder.)

NSMenu delegate not called to populate it

I have a controller object that owns an NSMenu and is that menu's delegate, in the interest of lazy population.
However, neither numberOfItemsInMenu: nor menuNeedsUpdate: is ever called, and so the menu remains empty.
I have confirmed that:
The controller object has not been deallocated. (The controller, in turn, owns the menu.)
It does have a menu.
The menu does have a delegate, and that is the controller.
If I implement menuWillOpen:, that is called, but you're not supposed to populate the menu there.
I tried sending the menu an update message, and that had no effect. The delegate remained un-called, and the menu remained empty.
In case it's relevant: This menu is not in the main menu; it is used elsewhere.
Why isn't the menu asking its delegate to populate it? Is there something I've missed, or is this just broken?
Maybe you need a strong reference to the delegate.
Try moving variable declaration out of your method and make a class-level member variable.
look at this answer: https://stackoverflow.com/a/21816149/1664943

NSMenuDelegate methods not called for contextual menu

I have a Document based application. I want to add a contextual menu that displays context-sensitive info when the user right-clicks selected text in an NSTextView.
I have followed the advice in the Apple documentation and
Added an NSMenu as a root object in my XIB file.
Connected the NSMenu instance to the menu outlet of the NSTextView.
Connected an IBAction to the NSMenuItem inside the NSMenu.
So far so good. Every thing works as expected: the menu item appears and the action is called when it is selected.
I need to get the selected text from the NSTextView before the menu appears so that I can configure my menu item appropriately. According to the docs
If you need to customize the contextual menu, you can do so by setting
an appropriate object as the menu’s delegate and implementing the
menuWillOpen: method to customize the menu as you see fit just before
it appears.
I connect the delegate of the NSMenu to File's Owner. None of the delegate methods are called. ( menuWillOpen: is the only one I need, but I've tried others, too).
I set a breakpoint inside the IBAction that gets called when the menu item is selected. If I inspect the menu with the debugger I can see that the delegate is correctly set to the object that implements the delegate method.
Is there anything else to check? Anything I'm doing blatantly wrong?
Xcode v4.6.3
SDK v10.8
Deployment target 10.7
After some digging, this is what I found: NSTextView builds a different NSMenu instance to use as the contextual menu, probably by overriding -menuForEvent: or some similar internal method. This new menu copies the menu items from the menu you created in Interface Builder (in fact, it creates new menu item instances whose attributes are copied from the original menu items) but it does not copy the menu delegate, which is why your menu delegate does not receive -menuWillOpen:. I am not sure whether this is intentional or not. Reading that documentation quote you posted, it seems to be a bug.
What you can do is to set the delegate of your NSTextView instance to an object whose class conforms to NSTextViewDelegate (maybe your File’s Owner, which already conforms to NSMenuDelegate) and implement the following method:
- (NSMenu *)textView:(NSTextView *)view menu:(NSMenu *)menu forEvent:(NSEvent *)event atIndex:(NSUInteger)charIndex
{
// if the menu delegate is not self, set another object
[menu setDelegate:self];
return menu;
}
This will make sure that the contextual menu created by the text view uses your delegate.
NB: since NSTextView creates a different contextual menu, it could be the case that it might want to set the menu delegate to itself or some other internal object. In my tests the delegate is nil, so it looks like it’s safe. Alternatively, you could discard the proposed menu argument and return your own NSMenu instance with the delegate correctly set.
Finding this thread saved me a lot of time...thanks! Here's an implementation that works in an NSView in Swift. myNSMenu is an outlet from Storyboard to appDelegate and a subclass of NSMenu. Without the assignment of the delegate in the code below, the NSMenuDelegate functions were not called.
let appDelegate = NSApplication.sharedApplication().delegate as! AppDelegate
appDelegate.myNSMenu.delegate = appDelegate.myNSMenu
NSMenu.popUpContextMenu(appDelegate.myNSMenu, withEvent: theEvent, forView: self)

Setting NSDocument as delegate of NSMenu

I have a menu item whose state should depend on whichever NSDocument is open. From my understanding, to make its state change dynamically I should use the NSMenu delegate method menuNeedsUpdate:.
It seems like I would want to have the menu's delegate be the First Responder in MainMenu.xib. However, Interface Builder won't let me set it as the Main Menu's delegate. How can I make a delegate which will be able to access the currently active document?
I generally make such changes in the validateMenuItem: method being called before the menu is shown. The receiver of the action is asked whether the item is to be enabled or not. But you can do pretty much any change there. Since 10.5 it is also safe to add and remove items during such a call.

First item in an NSMenu does not appear

I am making my own NSMenu programmatically and popping it up when a button is pressed.
I create NSMenuItems and add them with the NSMenu method insertItem:atIndex:.
For some reason whatever item is at position zero in the menu does not show up. Is this how the menu is supposed to work?
Yes, this is how the menu is supposed to work, if the NSPopUpButton pullsDown. The first item corresponds to the title of the button; just insert "" or whatever you want. It won't show up.
So you're building your menu in reverse order (by iteratively calling insertItem:anItem atIndex:0)? Why not just build it from the top down and successively call addItem:? I've done this lots and never had issues with items disappearing.

Resources