Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force NSToolBar validation?

I'm geting this strange behavior. I'm using a panel with text to show to the user when the app is waiting for some info. This panel is show modally to prevent the user to click something.

When the loading panel is hidden all the items on the toolbar are disabled and the validateToolbarItem method is not called.

I'm showing the panel in this way:

- (void)showInWindow:(NSWindow *)mainWindow {
 sheetWindow = [self window];
 [self sheetWillShow];

 [NSApp beginSheet:sheetWindow modalForWindow:mainWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
 [NSApp runModalForWindow:sheetWindow];
 [NSApp endSheet:sheetWindow];
 [sheetWindow orderOut:self]; 
}

- (void)dismissModal {
 [sheetWindow close];
 [NSApp stopModal];
}

How can I force the toolbar to validate in this case?

Edit after comment:

I have already tried:

  • [[[NSApp mainWindow] toolbar] validateVisibleItems]
  • [[NSApp mainWindow] update];
  • [NSApp updateWindows];
  • [NSApp setWindowsNeedUpdate:YES];

All after call dismissModal. I'm thinking that the problem is elsewhere....

like image 254
Bruno Berisso Avatar asked Dec 17 '10 18:12

Bruno Berisso


2 Answers

The problem is that NSToolbar only sends validation messages to NSToolbarItem's that are of Image type, which none of mine were. In order to validate any or all NSToolbarItems's, create a custom subclass of NSToolBar and override the validateVisibleItems: method. This will send validation messages to ALL visible NSToolbarItem's. The only real difference is that instead of having the Toolbar class enable or disable the item with the returned BOOL, you need to enable or disable the item in the validation method itself.

@interface CustomToolbar : NSToolbar
@end
@implementation CustomToolbar
-(void)validateVisibleItems
{
    for (NSToolbarItem *toolbarItem in self.visibleItems)
    {
        NSResponder *responder = toolbarItem.view;
        while ((responder = [responder nextResponder]))
        {
            if ([responder respondsToSelector:toolbarItem.action])
            {
                [responder performSelector:@selector(validateToolbarItem:) withObject:toolbarItem];
            }
        }
    }
}
@end

Now, assume you have a controller with an IBAction method that handles Actions for a NSSegmentedControl in your toolbar:

- (IBAction)backButton:(NSSegmentedControl*)sender
{
    NSInteger segment = sender.selectedSegment;
    if (segment == 0)
    {
        // Action for first button segment
    }
    else if (segment == 1)
    {
        // Action for second button segment
    }
}

Place the following in the same controller that handles the toolbar item's Action:

-(BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem
{
    SEL theAction = [toolbarItem action];
    if (theAction == @selector(backButton:))
    {
        [toolbarItem setEnabled:YES];

        NSSegmentedControl *backToolbarButton = (NSSegmentedControl *)toolbarItem.view;
        [backToolbarButton setEnabled:YES forSegment:0];
        [backToolbarButton setEnabled:NO forSegment:1];
    }
    return NO;
}

The result is that you have complete control over which segments are enabled or disabled.

This technique should be applicable to almost any other type of NSToolbarItem as long as the item's Received Action is being handled by a controller in the responder chain.

I hope this helps.

like image 181
Chuck H Avatar answered Nov 04 '22 04:11

Chuck H


NSToolbar *toolbar; //Get this somewhere. If you have the window it is in, call [window toolbar];
[toolbar validateVisibleItems];
like image 25
ughoavgfhw Avatar answered Nov 04 '22 04:11

ughoavgfhw