NSTableView : Context menu for editing column configuration - macos

In some OS X apps, control-clicking on the header of an NSTableView brings up a context menu, that lets the user choose which columns are visible.
Is this something I'll need to implement manually, or is this some hard to find Cocoa feature?

AFAIK, it isn't a standard feature of NSTableView. You have to implement it on your own by setting the menu of NSTableHeaderView.
NSMenu *menu = [[NSMenu alloc] initWithTitle:#""];
menu.font = [NSFont menuFontOfSize:[NSFont smallSystemFontSize]];
menu.showsStateColumn = YES;
for (NSTableColumn *column in tableView.tableColumns) {
NSMenuItem *item = [menu addItemWithTitle:column.headerToolTip action:#selector(toggleTableColumn:) keyEquivalent:#""];
item.state = [column isHidden] ? NSOffState : NSOnState;
item.representedObject = column;
}
tableView.headerView.menu = menu;

Related

How to get the selected NSMenuItem from a submenu?

I have an API that allows users to create popup menus with sub menus, and I'm having problems detecting the selected item when the user clicks on an option that belongs to a sub menu.
So, the display and "construction" of the popup menu is correct and it works fine. Starting from a NSMenu I add a few NSMenuItems, then for some NSMenuItems I add a new NSMenu with a few NSMenuItems more.
The problem begins when I click on an item that belongs to a submenu, the selectedItem I get is always nil. It works fine for the main menu. Here's how I show the menu:
NSRect frame = NSMakeRect(mp.origin.x + 10, mp.origin.y + 10, 1, 1);
NSPopUpButtonCell *cell = [[NSPopUpButtonCell alloc] initTextCell: #"" pullsDown: NO];
[cell setAutoenablesItems: NO];
[cell setAltersStateOfSelectedItem: NO];
[cell setMenu: mainMenu];
[cell selectItem: Nil];
[cell performClickWithFrame: frame inView: [window initialFirstResponder]];
NSMenuItem *xpto = [cell selectedItem];

Attach NSMenu to NSStatusItem with Storyboard

I am trying to attach an NSMenu item to a NSStatusItem to have a menu when clicking on my Menu Bar App for Mac OS.
I am new to Mac programming and I searched tutorials on the Web. However, all the material I found involves the usage of the file Xib to add the NSMenu and linking it to the existing code. However, I don't have such a file in my project, it only includes the storyboard file.
I hope you can help.
Cheers
You can create a menu programmatically and set it to NSStatusItem like this.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:30];
_statusItem.image = [NSImage imageNamed:#"..."];
// create menu
NSMenu *menu = [[NSMenu alloc] initWithTitle:#""];
NSMenuItem *item1 = [[NSMenuItem alloc] initWithTitle:#"menu1" action:#selector(menu1Action:) keyEquivalent:#""];
NSMenuItem *item2 = [[NSMenuItem alloc] initWithTitle:#"menu2" action:#selector(menu2Action:) keyEquivalent:#""];
[menu addItem:item1];
[menu addItem:item2];
[_statusItem setMenu:menu]; // attach
}
Of course, you can use NSMenu as outlet. To do that, drag NSMenu to Application Scene in the storyboard, and connect it to AppDelegate's outlet.

Hide NSMenu programmatically from NSStatusItem

I have this application that shows an item in the system's status bar, and one of the items is a custom view with a NSTextField and a NSButton. When the user clicks on the status bar item, it shows the menu, the user inputs some text and presses the button. This triggers an action that displays a window.
The problem I'm having now is, when the button is pressed it does trigger the action, but the menu remains visible. I want to hide the menu, because the action has already been processed.
I've searched through the API, but couldn't find how to do it.
Any ideas?
This is how I'm creating the menu:
NSStatusBar *bar = [NSStatusBar systemStatusBar];
self.statusItem = [bar statusItemWithLength:NSVariableStatusItemLength];
[statusItem setImage:[NSImage imageNamed:#"icon_status_bar.png"]];
[statusItem setHighlightMode:YES];
NSMenuItem *textInputItem = [[NSMenuItem alloc] initWithTitle:#"" action:nil keyEquivalent:#""];
[textInputItem setView:myCustomView]; // created on the Nib file...
NSMenu *menu = [[NSMenu alloc] initWithTitle:NSLocalizedString(#"statusBarMenuTitle", #"")];
[menu addItem:textInputItem];
[statusItem setMenu:menu];
[textInputItem release];
[menu release];
It's not obvious in the docs, but [menu cancelTracking] is what you want.
cancelTracking
Dismisses the menu and ends all menu tracking.
- (void)cancelTracking

adding NSSubmenu item in NSMenuItem

I want to add a drop down menu in one of the entries in the NSMenu Item. (eg. If you click on the Battery indicator on Finder bar, it has an option for Show->Icon,Time,Percentage).
Now I add a MenuItem using the following code:
menuItem = [menu addItemWithTitle:#"Start"
action:#selector(start:) keyEquivalent:#""];
[menuItem setTarget:self];
How do I add a submenu Item with this drop down list ? Thanks.
This is how I add a submenu to an NSMenu item:
NSMenuItem *mainItem = [[NSMenuItem alloc] init];
[mainItem setTitle:#"Main item"];
NSMenu *submenu = [[NSMenu alloc] init];
[submenu addItemWithTitle:#"Sub item" action:nil keyEquivalent:#""];
[mainItem setSubmenu:submenu];
Got it working. Created a NSPopuButton with contents from an array and then used that here.
[menu setSubmenu:[(NSPopupButton *array) menu] forItem:menuItem];

Clickable url link in NSTextFieldCell inside NSTableView?

I have a NSAttributedString that I'm using in a NSTextFieldCell. It makes several clickable url links and puts a big NSAttributedString inside the NSTextFieldCell. Whenever I am viewing the NSTextFieldCell normally and it's highlighted, I cannot click on the links.
If I set the TableView so I can edit each column or row, when I click twice, go into Edit mode and view the NSTextFieldCell contents, my links show up and are clickable. When I click away from the row, I can no longer see clickable links.
I have to be in "edit" mode to see the links or click on them.
I feel like there's some setting I'm just missing.
I don't think the tech note answers the question, which was how to put a link in an NSTableView cell. The best way I've found to do this is to use a button cell for the table cell. This assumes that only links will be in a particular column of the table.
In Interface Builder, drag an NSButton cell onto the table column where you want the links.
In your table view delegate, implement tableView:dataCellForTableColumn:row: as follows:
- (NSCell *) tableView: (NSTableView *) tableView
dataCellForTableColumn: (NSTableColumn *) column
row: (NSInteger) row
{
NSButtonCell *buttonCell = nil;
NSAttributedString *title = nil;
NSString *link = nil;
NSDictionary *attributes = nil;
// Cell for entire row -- we don't do headers
if (column == nil)
return(nil);
// Columns other than link do the normal thing
if (![self isLinkColumn:column]) // Implement this as appropriate for your table
return([column dataCellForRow:row]);
// If no link, no button, just a blank text field
if ((link = [self linkForRow:row]) != nil) // Implement this as appropriate for your table
return([[[NSTextFieldCell alloc] initTextCell:#""] autorelease]);
// It's a link. Create the title
attributes = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSFont systemFontOfSize:[NSFont systemFontSize]], NSFontAttributeName,
[NSNumber numberWithInt:NSUnderlineStyleSingle], NSUnderlineStyleAttributeName,
[NSColor blueColor], NSForegroundColorAttributeName,
[NSURL URLWithString:link], NSLinkAttributeName, nil];
title = [[NSAttributedString alloc] initWithString:link attributes:attributes];
[attributes release];
// Create a button cell
buttonCell = [[[NSButtonCell alloc] init] autorelease];
[buttonCell setBezelStyle:NSRoundedBezelStyle];
[buttonCell setButtonType:NSMomentaryPushInButton];
[buttonCell setBordered:NO]; // Don't want a bordered button
[buttonCell setAttributedTitle:title];
[title release];
return(buttonCell);
}
Set the target/action for the table to your delegate and check for clicks on the link column:
- (void) clickTable: (NSTableView *) sender
{
NSTableColumn *column = [[sender tableColumns] objectAtIndex:[sender clickedColumn]];
NSInteger row = [sender clickedRow];
NSString *link = nil;
if ([self isLinkColumn:column] && (link = [self linkForRow:row]) != nil)
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:link]];
}
Now the link looks like a link, but a click on it is actually a button press, which you detect in the action method and dispatch using NSWorkspace.
Have you seen this technical note from Apple regarding hyperlinks?
Embedding Hyperlinks in NSTextField and NSTextView

Resources