| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ui/base/cocoa/menu_controller.h" | 5 #import "ui/base/cocoa/menu_controller.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/strings/sys_string_conversions.h" | 8 #include "base/strings/sys_string_conversions.h" |
| 9 #include "ui/base/accelerators/accelerator.h" | 9 #include "ui/base/accelerators/accelerator.h" |
| 10 #include "ui/base/accelerators/platform_accelerator_cocoa.h" | 10 #include "ui/base/accelerators/platform_accelerator_cocoa.h" |
| 11 #include "ui/base/l10n/l10n_util_mac.h" | 11 #include "ui/base/l10n/l10n_util_mac.h" |
| 12 #include "ui/base/models/simple_menu_model.h" | 12 #include "ui/base/models/simple_menu_model.h" |
| 13 #import "ui/events/event_utils.h" | 13 #import "ui/events/event_utils.h" |
| 14 #include "ui/gfx/font_list.h" | 14 #include "ui/gfx/font_list.h" |
| 15 #include "ui/gfx/image/image.h" | 15 #include "ui/gfx/image/image.h" |
| 16 #include "ui/gfx/text_elider.h" | 16 #include "ui/gfx/text_elider.h" |
| 17 | 17 |
| 18 NSString* const kMenuControllerMenuWillOpenNotification = | 18 NSString* const kMenuControllerMenuWillOpenNotification = |
| 19 @"MenuControllerMenuWillOpen"; | 19 @"MenuControllerMenuWillOpen"; |
| 20 NSString* const kMenuControllerMenuDidCloseNotification = | 20 NSString* const kMenuControllerMenuDidCloseNotification = |
| 21 @"MenuControllerMenuDidClose"; | 21 @"MenuControllerMenuDidClose"; |
| 22 | 22 |
| 23 @interface MenuController (Private) | 23 @interface MenuController (Private) |
| 24 - (void)addSeparatorToMenu:(NSMenu*)menu | 24 - (void)addSeparatorToMenu:(NSMenu*)menu |
| 25 atIndex:(int)index; | 25 atIndex:(int)index; |
| 26 @end | 26 @end |
| 27 | 27 |
| 28 @interface ResponsiveNSMenuItem : NSMenuItem |
| 29 @end |
| 30 |
| 28 @implementation MenuController | 31 @implementation MenuController |
| 29 | 32 |
| 30 @synthesize model = model_; | 33 @synthesize model = model_; |
| 31 @synthesize useWithPopUpButtonCell = useWithPopUpButtonCell_; | 34 @synthesize useWithPopUpButtonCell = useWithPopUpButtonCell_; |
| 32 | 35 |
| 33 + (base::string16)elideMenuTitle:(const base::string16&)title | 36 + (base::string16)elideMenuTitle:(const base::string16&)title |
| 34 toWidth:(int)width { | 37 toWidth:(int)width { |
| 35 NSFont* nsfont = [NSFont menuBarFontOfSize:0]; // 0 means "default" | 38 NSFont* nsfont = [NSFont menuBarFontOfSize:0]; // 0 means "default" |
| 36 return gfx::ElideText(title, gfx::FontList(gfx::Font(nsfont)), width, | 39 return gfx::ElideText(title, gfx::FontList(gfx::Font(nsfont)), width, |
| 37 gfx::ELIDE_TAIL); | 40 gfx::ELIDE_TAIL); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 53 } | 56 } |
| 54 | 57 |
| 55 - (void)dealloc { | 58 - (void)dealloc { |
| 56 [menu_ setDelegate:nil]; | 59 [menu_ setDelegate:nil]; |
| 57 | 60 |
| 58 // Close the menu if it is still open. This could happen if a tab gets closed | 61 // Close the menu if it is still open. This could happen if a tab gets closed |
| 59 // while its context menu is still open. | 62 // while its context menu is still open. |
| 60 [self cancel]; | 63 [self cancel]; |
| 61 | 64 |
| 62 model_ = NULL; | 65 model_ = NULL; |
| 66 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 67 |
| 63 [super dealloc]; | 68 [super dealloc]; |
| 64 } | 69 } |
| 65 | 70 |
| 66 - (void)cancel { | 71 - (void)cancel { |
| 67 if (isMenuOpen_) { | 72 if (isMenuOpen_) { |
| 68 [menu_ cancelTracking]; | 73 [menu_ cancelTracking]; |
| 69 model_->MenuWillClose(); | 74 model_->MenuWillClose(); |
| 70 isMenuOpen_ = NO; | 75 isMenuOpen_ = NO; |
| 71 } | 76 } |
| 72 } | 77 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 // associated with the entry in the model identified by |modelIndex|. | 110 // associated with the entry in the model identified by |modelIndex|. |
| 106 - (void)addItemToMenu:(NSMenu*)menu | 111 - (void)addItemToMenu:(NSMenu*)menu |
| 107 atIndex:(NSInteger)index | 112 atIndex:(NSInteger)index |
| 108 fromModel:(ui::MenuModel*)model { | 113 fromModel:(ui::MenuModel*)model { |
| 109 base::string16 label16 = model->GetLabelAt(index); | 114 base::string16 label16 = model->GetLabelAt(index); |
| 110 int maxWidth = [self maxWidthForMenuModel:model modelIndex:index]; | 115 int maxWidth = [self maxWidthForMenuModel:model modelIndex:index]; |
| 111 if (maxWidth != -1) | 116 if (maxWidth != -1) |
| 112 label16 = [MenuController elideMenuTitle:label16 toWidth:maxWidth]; | 117 label16 = [MenuController elideMenuTitle:label16 toWidth:maxWidth]; |
| 113 | 118 |
| 114 NSString* label = l10n_util::FixUpWindowsStyleLabel(label16); | 119 NSString* label = l10n_util::FixUpWindowsStyleLabel(label16); |
| 115 base::scoped_nsobject<NSMenuItem> item( | 120 base::scoped_nsobject<NSMenuItem> item([[ResponsiveNSMenuItem alloc] |
| 116 [[NSMenuItem alloc] initWithTitle:label | 121 initWithTitle:label |
| 117 action:@selector(itemSelected:) | 122 action:@selector(itemSelected:) |
| 118 keyEquivalent:@""]); | 123 keyEquivalent:@""]); |
| 119 | 124 |
| 120 // If the menu item has an icon, set it. | 125 // If the menu item has an icon, set it. |
| 121 gfx::Image icon; | 126 gfx::Image icon; |
| 122 if (model->GetIconAt(index, &icon) && !icon.IsEmpty()) | 127 if (model->GetIconAt(index, &icon) && !icon.IsEmpty()) |
| 123 [item setImage:icon.ToNSImage()]; | 128 [item setImage:icon.ToNSImage()]; |
| 124 | 129 |
| 125 ui::MenuModel::ItemType type = model->GetTypeAt(index); | 130 ui::MenuModel::ItemType type = model->GetTypeAt(index); |
| 126 if (type == ui::MenuModel::TYPE_SUBMENU) { | 131 if (type == ui::MenuModel::TYPE_SUBMENU) { |
| 127 // Recursively build a submenu from the sub-model at this index. | 132 // Recursively build a submenu from the sub-model at this index. |
| 128 [item setTarget:nil]; | 133 [item setTarget:nil]; |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 base::scoped_nsobject<NSAttributedString> title( | 198 base::scoped_nsobject<NSAttributedString> title( |
| 194 [[NSAttributedString alloc] initWithString:[(id)item title] | 199 [[NSAttributedString alloc] initWithString:[(id)item title] |
| 195 attributes:attributes]); | 200 attributes:attributes]); |
| 196 [(id)item setAttributedTitle:title.get()]; | 201 [(id)item setAttributedTitle:title.get()]; |
| 197 } | 202 } |
| 198 return model->IsEnabledAt(modelIndex); | 203 return model->IsEnabledAt(modelIndex); |
| 199 } | 204 } |
| 200 return NO; | 205 return NO; |
| 201 } | 206 } |
| 202 | 207 |
| 203 // Called when the user chooses a particular menu item. |sender| is the menu | 208 - (void)itemWillBeSelected:(id)sender { |
| 204 // item chosen. | 209 suppressNextItemSelected_ = [self processItemSelectedEarly:sender]; |
| 210 } |
| 211 |
| 212 - (BOOL)processItemSelectedEarly:(id)sender { |
| 213 return NO; |
| 214 } |
| 215 |
| 205 - (void)itemSelected:(id)sender { | 216 - (void)itemSelected:(id)sender { |
| 217 DLOG(INFO) << "got action"; |
| 218 if (suppressNextItemSelected_) |
| 219 return; |
| 220 |
| 206 NSInteger modelIndex = [sender tag]; | 221 NSInteger modelIndex = [sender tag]; |
| 207 ui::MenuModel* model = | 222 ui::MenuModel* model = |
| 208 static_cast<ui::MenuModel*>( | 223 static_cast<ui::MenuModel*>( |
| 209 [[sender representedObject] pointerValue]); | 224 [[sender representedObject] pointerValue]); |
| 210 DCHECK(model); | 225 DCHECK(model); |
| 211 if (model) { | 226 if (model) { |
| 212 int event_flags = ui::EventFlagsFromNative([NSApp currentEvent]); | 227 int event_flags = ui::EventFlagsFromNative([NSApp currentEvent]); |
| 213 model->ActivatedAt(modelIndex, event_flags); | 228 model->ActivatedAt(modelIndex, event_flags); |
| 214 } | 229 } |
| 215 } | 230 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 230 } | 245 } |
| 231 return menu_.get(); | 246 return menu_.get(); |
| 232 } | 247 } |
| 233 | 248 |
| 234 - (BOOL)isMenuOpen { | 249 - (BOOL)isMenuOpen { |
| 235 return isMenuOpen_; | 250 return isMenuOpen_; |
| 236 } | 251 } |
| 237 | 252 |
| 238 - (void)menuWillOpen:(NSMenu*)menu { | 253 - (void)menuWillOpen:(NSMenu*)menu { |
| 239 isMenuOpen_ = YES; | 254 isMenuOpen_ = YES; |
| 255 suppressNextItemSelected_ = NO; |
| 240 model_->MenuWillShow(); | 256 model_->MenuWillShow(); |
| 241 [[NSNotificationCenter defaultCenter] | 257 [[NSNotificationCenter defaultCenter] |
| 242 postNotificationName:kMenuControllerMenuWillOpenNotification | 258 postNotificationName:kMenuControllerMenuWillOpenNotification |
| 243 object:self]; | 259 object:self]; |
| 260 [[NSNotificationCenter defaultCenter] |
| 261 addObserver:self |
| 262 selector:@selector(willSendAction:) |
| 263 name:NSMenuWillSendActionNotification |
| 264 object:nil]; |
| 244 } | 265 } |
| 245 | 266 |
| 246 - (void)menuDidClose:(NSMenu*)menu { | 267 - (void)menuDidClose:(NSMenu*)menu { |
| 268 DLOG(INFO) << "did close"; |
| 247 if (isMenuOpen_) { | 269 if (isMenuOpen_) { |
| 248 model_->MenuWillClose(); | 270 model_->MenuWillClose(); |
| 249 isMenuOpen_ = NO; | 271 isMenuOpen_ = NO; |
| 250 } | 272 } |
| 251 [[NSNotificationCenter defaultCenter] | 273 [[NSNotificationCenter defaultCenter] |
| 252 postNotificationName:kMenuControllerMenuDidCloseNotification | 274 postNotificationName:kMenuControllerMenuDidCloseNotification |
| 253 object:self]; | 275 object:self]; |
| 254 } | 276 } |
| 255 | 277 |
| 278 - (void)willSendAction:(NSNotification*)note { |
| 279 DLOG(INFO) << "will send action"; |
| 280 } |
| 281 |
| 256 @end | 282 @end |
| 283 |
| 284 @interface NSMenuItem (Private) |
| 285 // Private method which is invoked very soon after the event that activates a |
| 286 // menu item is received. AppKit then spends 300ms or so flashing the menu item, |
| 287 // and fading out the menu, blocking the UI thread the entire time. |
| 288 - (void)_sendItemSelectedNote; |
| 289 @end |
| 290 |
| 291 @implementation ResponsiveNSMenuItem |
| 292 - (void)_sendItemSelectedNote { |
| 293 DLOG(INFO) << "early"; |
| 294 if ([[self target] respondsToSelector:@selector(itemWillBeSelected:)]) |
| 295 [[self target] itemWillBeSelected:self]; |
| 296 [super _sendItemSelectedNote]; |
| 297 } |
| 298 @end |
| OLD | NEW |