Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / tabs / tab_controller.mm
index 47f844c..4370557 100644 (file)
 #include "base/i18n/rtl.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/mac_util.h"
-#include "base/strings/sys_string_conversions.h"
 #import "chrome/browser/themes/theme_properties.h"
 #import "chrome/browser/themes/theme_service.h"
-#import "chrome/browser/ui/cocoa/tabs/media_indicator_view.h"
+#import "chrome/browser/ui/cocoa/sprite_view.h"
+#import "chrome/browser/ui/cocoa/tabs/media_indicator_button.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
 #import "chrome/browser/ui/cocoa/themed_window.h"
-#import "chrome/common/extensions/extension.h"
-#include "grit/generated_resources.h"
-#import "third_party/GTM/AppKit/GTMFadeTruncatingTextFieldCell.h"
+#include "content/public/browser/user_metrics.h"
+#import "extensions/common/extension.h"
 #import "ui/base/cocoa/menu_controller.h"
-#include "ui/base/l10n/l10n_util_mac.h"
 
 @implementation TabController
 
@@ -45,18 +43,17 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
         owner_(owner) {}
 
   // Overridden from ui::SimpleMenuModel::Delegate
-  virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
-    return false;
-  }
-  virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
+  bool IsCommandIdChecked(int command_id) const override { return false; }
+  bool IsCommandIdEnabled(int command_id) const override {
     TabStripModel::ContextMenuCommand command =
         static_cast<TabStripModel::ContextMenuCommand>(command_id);
     return [target_ isCommandEnabled:command forController:owner_];
   }
-  virtual bool GetAcceleratorForCommandId(
-      int command_id,
-      ui::Accelerator* accelerator) OVERRIDE { return false; }
-  virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE {
+  bool GetAcceleratorForCommandId(int command_id,
+                                  ui::Accelerator* accelerator) override {
+    return false;
+  }
+  void ExecuteCommand(int command_id, int event_flags) override {
     TabStripModel::ContextMenuCommand command =
         static_cast<TabStripModel::ContextMenuCommand>(command_id);
     [target_ commandDispatch:command forController:owner_];
@@ -74,7 +71,7 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
 // of the two tab edge bitmaps because these bitmaps have a few transparent
 // pixels on the side.  The selected tab width includes the close button width.
 + (CGFloat)minTabWidth { return 36; }
-+ (CGFloat)minSelectedTabWidth { return 52; }
++ (CGFloat)minActiveTabWidth { return 52; }
 + (CGFloat)maxTabWidth { return 214; }
 + (CGFloat)miniTabWidth { return 58; }
 + (CGFloat)appTabWidth { return 66; }
@@ -90,30 +87,17 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
     // Remember the icon's frame, so that if the icon is ever removed, a new
     // one can later replace it in the proper location.
     originalIconFrame_ = NSMakeRect(19, 5, 16, 16);
-    iconView_.reset([[NSImageView alloc] initWithFrame:originalIconFrame_]);
-    [iconView_ setAutoresizingMask:NSViewMaxXMargin];
+    iconView_.reset([[SpriteView alloc] initWithFrame:originalIconFrame_]);
+    [iconView_ setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
 
     // When the icon is removed, the title expands to the left to fill the
     // space left by the icon.  When the close button is removed, the title
     // expands to the right to fill its space.  These are the amounts to expand
-    // and contract titleView_ under those conditions. We don't have to
+    // and contract the title frame under those conditions. We don't have to
     // explicilty save the offset between the title and the close button since
     // we can just get that value for the close button's frame.
     NSRect titleFrame = NSMakeRect(35, 6, 92, 14);
 
-    // Label.
-    titleView_.reset([[NSTextField alloc] initWithFrame:titleFrame]);
-    [titleView_ setAutoresizingMask:NSViewWidthSizable];
-    base::scoped_nsobject<GTMFadeTruncatingTextFieldCell> labelCell(
-        [[GTMFadeTruncatingTextFieldCell alloc] initTextCell:@"Label"]);
-    [labelCell setControlSize:NSSmallControlSize];
-    CGFloat fontSize = [NSFont systemFontSizeForControlSize:NSSmallControlSize];
-    NSFont* font = [NSFont fontWithName:
-        [[labelCell font] fontName] size:fontSize];
-    [labelCell setFont:font];
-    [titleView_ setCell:labelCell];
-    titleViewCell_ = labelCell;
-
     // Close button.
     closeButton_.reset([[HoverCloseButton alloc] initWithFrame:
         NSMakeRect(127, 4, 18, 18)]);
@@ -127,8 +111,8 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
                            closeButton:closeButton_]);
     [view setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
     [view addSubview:iconView_];
-    [view addSubview:titleView_];
     [view addSubview:closeButton_];
+    [view setTitleFrame:titleFrame];
     [super setView:view];
 
     isIconShowing_ = YES;
@@ -144,6 +128,8 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
 }
 
 - (void)dealloc {
+  [mediaIndicatorButton_ setAnimationDoneTarget:nil withAction:nil];
+  [mediaIndicatorButton_ setClickTarget:nil withAction:nil];
   [[NSNotificationCenter defaultCenter] removeObserver:self];
   [[self tabView] setController:nil];
   [super dealloc];
@@ -154,10 +140,12 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
 // a re-draw.
 - (void)internalSetSelected:(BOOL)selected {
   TabView* tabView = [self tabView];
-  DCHECK([tabView isKindOfClass:[TabView class]]);
-  [tabView setState:selected];
-  if ([self active])
+  if ([self active]) {
+    [tabView setState:NSOnState];
     [tabView cancelAlert];
+  } else {
+    [tabView setState:selected ? NSMixedState : NSOffState];
+  }
   [self updateVisibility];
   [self updateTitleColor];
 }
@@ -177,7 +165,29 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
   return [contextMenuController_ menu];
 }
 
+- (void)toggleMute:(id)sender {
+  if ([[self target] respondsToSelector:@selector(toggleMute:)]) {
+    [[self target] performSelector:@selector(toggleMute:)
+                        withObject:[self view]];
+  }
+}
+
 - (void)closeTab:(id)sender {
+  using base::UserMetricsAction;
+
+  if (mediaIndicatorButton_ && ![mediaIndicatorButton_ isHidden]) {
+    if ([mediaIndicatorButton_ isEnabled]) {
+      content::RecordAction(UserMetricsAction("CloseTab_MuteToggleAvailable"));
+    } else if ([mediaIndicatorButton_ showingMediaState] ==
+                   TAB_MEDIA_STATE_AUDIO_PLAYING) {
+      content::RecordAction(UserMetricsAction("CloseTab_AudioIndicator"));
+    } else {
+      content::RecordAction(UserMetricsAction("CloseTab_RecordingIndicator"));
+    }
+  } else {
+    content::RecordAction(UserMetricsAction("CloseTab_NoMediaIndicator"));
+  }
+
   if ([[self target] respondsToSelector:@selector(closeTab:)]) {
     [[self target] performSelector:@selector(closeTab:)
                         withObject:[self view]];
@@ -194,16 +204,13 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
 }
 
 - (void)setTitle:(NSString*)title {
-  [titleView_ setStringValue:title];
-  base::string16 title16 = base::SysNSStringToUTF16(title);
-  bool isRTL = base::i18n::GetFirstStrongCharacterDirection(title16) ==
-               base::i18n::RIGHT_TO_LEFT;
-  titleViewCell_.truncateMode = isRTL ? GTMFadeTruncatingHead
-                                      : GTMFadeTruncatingTail;
-
-  if ([self mini] && ![self selected]) {
-    TabView* tabView = static_cast<TabView*>([self view]);
-    DCHECK([tabView isKindOfClass:[TabView class]]);
+  if ([[self title] isEqualToString:title])
+    return;
+
+  TabView* tabView = [self tabView];
+  [tabView setTitle:title];
+
+  if ([self mini] && ![self active]) {
     [tabView startAlert];
   }
   [super setTitle:title];
@@ -235,50 +242,33 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
   return selected_ || active_;
 }
 
-- (NSView*)iconView {
+- (SpriteView*)iconView {
   return iconView_;
 }
 
-- (void)setIconView:(NSView*)iconView {
+- (void)setIconView:(SpriteView*)iconView {
   [iconView_ removeFromSuperview];
   iconView_.reset([iconView retain]);
 
-  if ([self app] || [self mini]) {
-    NSRect appIconFrame = [iconView frame];
-    appIconFrame.origin = originalIconFrame_.origin;
-
-    const CGFloat tabWidth = [self app] ? [TabController appTabWidth]
-                                        : [TabController miniTabWidth];
-
-    // Center the icon.
-    appIconFrame.origin.x =
-        std::floor((tabWidth - NSWidth(appIconFrame)) / 2.0);
-    [iconView_ setFrame:appIconFrame];
-  } else {
-    [iconView_ setFrame:originalIconFrame_];
-  }
-  // Ensure that the icon is suppressed if no icon is set or if the tab is too
-  // narrow to display one.
-  [self updateVisibility];
-
   if (iconView_)
     [[self view] addSubview:iconView_];
 }
 
-- (NSTextField*)titleView {
-  return titleView_;
+- (MediaIndicatorButton*)mediaIndicatorButton {
+  return mediaIndicatorButton_;
 }
 
-- (MediaIndicatorView*)mediaIndicatorView {
-  return mediaIndicatorView_;
-}
-
-- (void)setMediaIndicatorView:(MediaIndicatorView*)mediaIndicatorView {
-  [mediaIndicatorView_ removeFromSuperview];
-  mediaIndicatorView_.reset([mediaIndicatorView retain]);
-  [self updateVisibility];
-  if (mediaIndicatorView_)
-    [[self view] addSubview:mediaIndicatorView_];
+- (void)setMediaState:(TabMediaState)mediaState {
+  if (!mediaIndicatorButton_ && mediaState != TAB_MEDIA_STATE_NONE) {
+    mediaIndicatorButton_.reset([[MediaIndicatorButton alloc] init]);
+    [self updateVisibility];  // Do layout and visibility before adding subview.
+    [[self view] addSubview:mediaIndicatorButton_];
+    [mediaIndicatorButton_ setAnimationDoneTarget:self
+                                       withAction:@selector(updateVisibility)];
+    [mediaIndicatorButton_ setClickTarget:self
+                               withAction:@selector(toggleMute:)];
+  }
+  [mediaIndicatorButton_ transitionToMediaState:mediaState];
 }
 
 - (HoverCloseButton*)closeButton {
@@ -306,22 +296,54 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
 
 - (BOOL)shouldShowIcon {
   return chrome::ShouldTabShowFavicon(
-      [self iconCapacity], [self mini], [self selected], iconView_ != nil,
-      !mediaIndicatorView_ ? TAB_MEDIA_STATE_NONE :
-          [mediaIndicatorView_ animatingMediaState]);
+      [self iconCapacity], [self mini], [self active], iconView_ != nil,
+      !mediaIndicatorButton_ ? TAB_MEDIA_STATE_NONE :
+          [mediaIndicatorButton_ showingMediaState]);
 }
 
 - (BOOL)shouldShowMediaIndicator {
-  if (!mediaIndicatorView_)
-    return NO;
   return chrome::ShouldTabShowMediaIndicator(
-      [self iconCapacity], [self mini], [self selected], iconView_ != nil,
-      [mediaIndicatorView_ animatingMediaState]);
+      [self iconCapacity], [self mini], [self active], iconView_ != nil,
+      !mediaIndicatorButton_ ? TAB_MEDIA_STATE_NONE :
+          [mediaIndicatorButton_ showingMediaState]);
 }
 
 - (BOOL)shouldShowCloseButton {
   return chrome::ShouldTabShowCloseButton(
-      [self iconCapacity], [self mini], [self selected]);
+      [self iconCapacity], [self mini], [self active]);
+}
+
+- (void)setIconImage:(NSImage*)image {
+  [self setIconImage:image withToastAnimation:NO];
+}
+
+- (void)setIconImage:(NSImage*)image withToastAnimation:(BOOL)animate {
+  if (image == nil) {
+    [self setIconView:nil];
+  } else {
+    if (iconView_.get() == nil) {
+      base::scoped_nsobject<SpriteView> iconView([[SpriteView alloc] init]);
+      [iconView setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
+      [self setIconView:iconView];
+    }
+
+    [iconView_ setImage:image withToastAnimation:animate];
+
+    if ([self app] || [self mini]) {
+      NSRect appIconFrame = [iconView_ frame];
+      appIconFrame.origin = originalIconFrame_.origin;
+
+      const CGFloat tabWidth = [self app] ? [TabController appTabWidth]
+                                          : [TabController miniTabWidth];
+
+      // Center the icon.
+      appIconFrame.origin.x =
+          std::floor((tabWidth - NSWidth(appIconFrame)) / 2.0);
+      [iconView_ setFrame:appIconFrame];
+    } else {
+      [iconView_ setFrame:originalIconFrame_];
+    }
+  }
 }
 
 - (void)updateVisibility {
@@ -334,7 +356,8 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
   isIconShowing_ = newShowIcon;
 
   // If the tab is a mini-tab, hide the title.
-  [titleView_ setHidden:[self mini]];
+  TabView* tabView = [self tabView];
+  [tabView setTitleHidden:[self mini]];
 
   BOOL newShowCloseButton = [self shouldShowCloseButton];
 
@@ -342,10 +365,11 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
 
   BOOL newShowMediaIndicator = [self shouldShowMediaIndicator];
 
-  [mediaIndicatorView_ setHidden:!newShowMediaIndicator];
+  [mediaIndicatorButton_ setHidden:!newShowMediaIndicator];
 
   if (newShowMediaIndicator) {
-    NSRect newFrame = [mediaIndicatorView_ frame];
+    NSRect newFrame = [mediaIndicatorButton_ frame];
+    newFrame.size = [[mediaIndicatorButton_ image] size];
     if ([self app] || [self mini]) {
       // Tab is pinned: Position the media indicator in the center.
       const CGFloat tabWidth = [self app] ?
@@ -354,7 +378,7 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
       newFrame.origin.y = NSMinY(originalIconFrame_) -
           std::floor((NSHeight(newFrame) - NSHeight(originalIconFrame_)) / 2);
     } else {
-      // The Frame for the mediaIndicatorView_ depends on whether iconView_
+      // The Frame for the mediaIndicatorButton_ depends on whether iconView_
       // and/or closeButton_ are visible, and where they have been positioned.
       const NSRect closeButtonFrame = [closeButton_ frame];
       newFrame.origin.x = NSMinX(closeButtonFrame);
@@ -365,12 +389,12 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
       newFrame.origin.y = NSMinY(closeButtonFrame) -
           std::floor((NSHeight(newFrame) - NSHeight(closeButtonFrame)) / 2);
     }
-    [mediaIndicatorView_ setFrame:newFrame];
+    [mediaIndicatorButton_ setFrame:newFrame];
   }
 
   // Adjust the title view based on changes to the icon's and close button's
   // visibility.
-  NSRect oldTitleFrame = [titleView_ frame];
+  NSRect oldTitleFrame = [tabView titleFrame];
   NSRect newTitleFrame;
   newTitleFrame.size.height = oldTitleFrame.size.height;
   newTitleFrame.origin.y = oldTitleFrame.origin.y;
@@ -382,7 +406,7 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
   }
 
   if (newShowMediaIndicator) {
-    newTitleFrame.size.width = NSMinX([mediaIndicatorView_ frame]) -
+    newTitleFrame.size.width = NSMinX([mediaIndicatorButton_ frame]) -
                                newTitleFrame.origin.x;
   } else if (newShowCloseButton) {
     newTitleFrame.size.width = NSMinX([closeButton_ frame]) -
@@ -392,7 +416,7 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
                                newTitleFrame.origin.x;
   }
 
-  [titleView_ setFrame:newTitleFrame];
+  [tabView setTitleFrame:newTitleFrame];
 }
 
 - (void)updateTitleColor {
@@ -403,7 +427,7 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate {
   // Default to the selected text color unless told otherwise.
   if (theme && !titleColor)
     titleColor = theme->GetNSColor(ThemeProperties::COLOR_TAB_TEXT);
-  [titleView_ setTextColor:titleColor ? titleColor : [NSColor textColor]];
+  [[self tabView] setTitleColor:titleColor ? titleColor : [NSColor textColor]];
 }
 
 - (void)themeChangedNotification:(NSNotification*)notification {