Appropriate place for menuNeedsUpdate?

Tags ( )

There are several menuNeedsUpdate methods for various popup menus, but there doesn't appear to be a menu delegate set in the MIUserInterface nib and hence it isn't clear to me where the best places is to put a menuNeedsUpdate method.

The obvious thing, to me, is to make MIUserInterfaceController the menu delegate -- but it seems way far removed from MIDocumentWindowController. Okay, so two questions:

a) is there a better place to put the menu delegate? I guess I could programmatically wire MIDocumentWindowController as the menu delegate rather than in IB, but MIUserInterfaceController seems like the right place for it.

b) Thus showing my lack of significant Cocoa experience, I'm betting that there is a way from within the MIUserInterfaceController to get the handle to the MIDocumentWindowController, yes?

Gavin.

Can you describe what your

Can you describe what your end goal is? Each NSMenu may (most do not) have a delegate, if the menu has a delegate then menuNeedsUpdate will be called on that delegate. Note that each submenu is also a is really a new NSMenu, so their are many NSMenu's and the possibility of many different menu delegates.

The only time (well the most common time, maybe there are others) that you need to set a delegate is when a menu will have a variable number of items, such as the columns list, or the different menu's that list Mori entries.

The general way to implement a dynamic menu would be.

1. Insert a new menu item by creating a class that extends BKMenuContributerProtocol, and make that class extend some menu extension point, such as com.hogbaysoftware.ui.mainmenu.

2. That allows you to insert a single menu item that you have control over. Now you can add a submenu to that item, and make one of you classes the delegate of that submenu. And you can implement menuNeedsUpdate in that delegate class and that's how you get a dynamic menu.

Let me know if that helps. In general you're delving into what I think is the worst designed/hardest to use part of Blocks. If you have ideas for making the menu extension system easier/better please let me know! :)

Jesse

Hi Jesse, Thanks for the

Hi Jesse,

Thanks for the info on BKMenuContributerProtocol. But, in this case, what I need the menuNeedsUpdate for is to check the collapsed state of the source list split-subview and ensure that a menu item in the View menu is set to one of "Hide Source List" or "Show Source List" (based on whether the source list is collapsed or not).

I've used menu delegates in my own Cocoa work, but I've always just wired them up from within IB. I see now that MIUserInterfaceMainMenuExtension extends BKMenuContributerProtocol and indeed there is one place where it does a setDelegate: self. I'll follow that and see if I get success.

Thanks.

Gavin.

Generally you don't use

Generally you don't use menuNeedsUpdate for this. Instead use automatic menu enabling:

http://developer.apple.com/documentation/Cocoa/Conceptual/MenuList/index.html#//apple_ref/doc/uid/10000032i

In this case I think you can follow the same pattern that I use for validating the Window > Float Window menu item. You'll need to add two methods to MIDocumentWindowController that follow this pattern:

// the action method that the menu item should target
- (IBAction)toggleFloatWindow:(id)sender {
NSWindow *window = [self window];
if ([window level] == NSFloatingWindowLevel) {
[window setLevel:NSNormalWindowLevel];
} else {
[window setLevel:NSFloatingWindowLevel];
}
}

// this method will automatically get called to validate your menu item.
// note that this method is a Mori specific convention in a generic cocoa app
// you will use validateMenuItem: to do this. The reason Mori does it different
// is because Mori will chanel all user interface validation to this method (for example also validation of NSToolbarItems.
- (NSNumber *)validatetoggleFloatWindow:(id)sender {
NSWindow *window = [self window];
if ([window level] == NSFloatingWindowLevel) {
[sender setState:NSOnState];
} else {
[sender setState:NSOffState];
}
return [NSNumber numberWithBool:YES];
}

Right -- if there were

Right -- if there were separate Hide Source List and Show Source List items, one of which were alternately enabled/disabled based on the non/collapsed state of the source list, then I'd expect to be using the validateMenuItem.

But when I've got one menu item where the text of the menu item changes based on the state of the source list to either Show Source List or Hide Source List, then my understanding was that menuNeedsUpdate is the conventional technique. Or it is at least what I think I learned from the Hillegass book and the menuNeedsUpdate docs. :-)

Gavin.

You should be able to handle

You should be able to handle that case to using the above method. Give your single menu item an action named something like toggleSourcesView:. That action will contain the logic that decides if the view should be opened or closed based on its current state.

Then in your validatetoggleSourcesView: method you will check the current view state, and if the sources view is showing you'll set the column label to "Hide" or if the sources view is not showing you'll set the menu label to "Show".

- (NSNumber *)validatetoggleSourcesView:(id)sender {
if ([self sourcesViewIsShowing]) {
[sender setTitle:BKLocalizedString(@"Hide", @"")];
} else {
[sender setTitle:BKLocalizedString(@"Show", @"")];
}
return [NSNumber numberWithBool:YES];
}

I'm pretty sure that menuNeedsUpdate only needs to be used for dynamic menus where the number of items is changing. The problem with using the delegate/menuNeedsUpdate pattern is that the delegate all of the sudden needs to peek into and know about the target of the menu. For instance the Cut menu item works on text, the sources view, and the entry view. If we just use the delegate/menuNeedsUpdate method to validate that menu item then the delegate will need to know about all of these views.

But using the automatic update/validateMenuItem pattern allows each of these different views to handle the menu validation itself.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.