summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbeng@google.com <beng@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-07 18:28:35 +0000
committerbeng@google.com <beng@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-07 18:28:35 +0000
commita6b4a185656b7b16d965e5ff0e469658c424e85d (patch)
tree4112198f2f85677b00d3a81b4c6e7d4033816ef6
parentf197851787237e4fa2d343f536f8fc7231316168 (diff)
downloadchromium_src-a6b4a185656b7b16d965e5ff0e469658c424e85d.zip
chromium_src-a6b4a185656b7b16d965e5ff0e469658c424e85d.tar.gz
chromium_src-a6b4a185656b7b16d965e5ff0e469658c424e85d.tar.bz2
Make tabs affected by context menu actions pulse. The effect is somewhat subtle since I'm re-using the selection animation.
Added support to the Menu Delegate for notifications of when selection moves within the menu. B=1313339 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@523 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/tabs/tab.cc134
-rw-r--r--chrome/browser/tabs/tab.h24
-rw-r--r--chrome/browser/tabs/tab_renderer.cc77
-rw-r--r--chrome/browser/tabs/tab_renderer.h15
-rw-r--r--chrome/browser/tabs/tab_strip.cc46
-rw-r--r--chrome/browser/tabs/tab_strip.h5
-rw-r--r--chrome/browser/tabs/tab_strip_model.cc10
-rw-r--r--chrome/browser/tabs/tab_strip_model.h4
-rw-r--r--chrome/views/chrome_menu.cc3
-rw-r--r--chrome/views/chrome_menu.h4
10 files changed, 248 insertions, 74 deletions
diff --git a/chrome/browser/tabs/tab.cc b/chrome/browser/tabs/tab.cc
index df02a15..f253faa 100644
--- a/chrome/browser/tabs/tab.cc
+++ b/chrome/browser/tabs/tab.cc
@@ -36,11 +36,93 @@
#include "chrome/browser/user_metrics.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/resource_bundle.h"
+#include "chrome/views/chrome_menu.h"
#include "chrome/views/tooltip_manager.h"
#include "generated_resources.h"
const std::string Tab::kTabClassName = "browser/tabs/Tab";
+class TabContextMenuController : public ChromeViews::MenuDelegate {
+ public:
+ explicit TabContextMenuController(Tab* tab)
+ : tab_(tab),
+ last_command_(TabStripModel::CommandFirst) {
+ menu_.reset(new ChromeViews::MenuItemView(this));
+ menu_->AppendMenuItemWithLabel(TabStripModel::CommandNewTab,
+ l10n_util::GetString(IDS_TAB_CXMENU_NEWTAB));
+ menu_->AppendSeparator();
+ menu_->AppendMenuItemWithLabel(TabStripModel::CommandReload,
+ l10n_util::GetString(IDS_TAB_CXMENU_RELOAD));
+ menu_->AppendMenuItemWithLabel(
+ TabStripModel::CommandDuplicate,
+ l10n_util::GetString(IDS_TAB_CXMENU_DUPLICATE));
+ menu_->AppendSeparator();
+ menu_->AppendMenuItemWithLabel(
+ TabStripModel::CommandCloseTab,
+ l10n_util::GetString(IDS_TAB_CXMENU_CLOSETAB));
+ menu_->AppendMenuItemWithLabel(
+ TabStripModel::CommandCloseOtherTabs,
+ l10n_util::GetString(IDS_TAB_CXMENU_CLOSEOTHERTABS));
+ menu_->AppendMenuItemWithLabel(
+ TabStripModel::CommandCloseTabsToRight,
+ l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSTORIGHT));
+ menu_->AppendMenuItemWithLabel(
+ TabStripModel::CommandCloseTabsOpenedBy,
+ l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSOPENEDBY));
+ }
+ virtual ~TabContextMenuController() {
+ tab_->delegate()->StopAllHighlighting();
+ }
+
+ void RunMenuAt(int x, int y) {
+ menu_->RunMenuAt(tab_->GetViewContainer()->GetHWND(),
+ gfx::Rect(x, y, 0, 0), ChromeViews::MenuItemView::TOPLEFT,
+ false);
+ }
+
+ private:
+ // ChromeViews::MenuDelegate implementation:
+ virtual bool IsCommandEnabled(int id) const {
+ // The MenuItemView used to contain the contents of the Context Menu itself
+ // has a command id of 0, and it will check to see if it's enabled for
+ // some reason during its construction. The TabStripModel can't handle
+ // command indices it doesn't know about, so we need to filter this out
+ // here.
+ if (id == 0)
+ return false;
+ return tab_->delegate()->IsCommandEnabledForTab(
+ static_cast<TabStripModel::ContextMenuCommand>(id),
+ tab_);
+ }
+
+ virtual void ExecuteCommand(int id) {
+ tab_->delegate()->ExecuteCommandForTab(
+ static_cast<TabStripModel::ContextMenuCommand>(id),
+ tab_);
+ }
+
+ virtual void SelectionChanged(ChromeViews::MenuItemView* menu) {
+ TabStripModel::ContextMenuCommand command =
+ static_cast<TabStripModel::ContextMenuCommand>(menu->GetCommand());
+ tab_->delegate()->StopHighlightTabsForCommand(last_command_, tab_);
+ last_command_ = command;
+ tab_->delegate()->StartHighlightTabsForCommand(command, tab_);
+ }
+
+ private:
+ // The context menu.
+ scoped_ptr<ChromeViews::MenuItemView> menu_;
+
+ // The Tab the context menu was brought up for.
+ Tab* tab_;
+
+ // The last command that was selected, so that we can start/stop highlighting
+ // appropriately as the user moves through the menu.
+ TabStripModel::ContextMenuCommand last_command_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TabContextMenuController);
+};
+
///////////////////////////////////////////////////////////////////////////////
// Tab, public:
@@ -51,6 +133,7 @@ Tab::Tab(TabDelegate* delegate)
close_button()->SetListener(this, 0);
close_button()->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE));
close_button()->SetAnimationDuration(0);
+ SetContextMenuController(this);
}
Tab::~Tab() {
@@ -89,13 +172,8 @@ void Tab::OnMouseReleased(const ChromeViews::MouseEvent& event,
// Notify the drag helper that we're done with any potential drag operations.
// Clean up the drag helper, which is re-created on the next mouse press.
delegate_->EndDrag(canceled);
- if (event.IsOnlyRightMouseButton()) {
- CPoint screen_point = event.GetLocation();
- ConvertPointToScreen(this, &screen_point);
- RunContextMenuAt(gfx::Point(screen_point));
- } else if (event.IsMiddleMouseButton()) {
+ if (event.IsMiddleMouseButton())
delegate_->CloseTab(this);
- }
}
bool Tab::GetTooltipText(int x, int y, std::wstring* tooltip) {
@@ -132,17 +210,14 @@ bool Tab::GetAccessibleName(std::wstring* name) {
}
///////////////////////////////////////////////////////////////////////////////
-// Tab, ChromeViews::Menu::Delegate implementation:
+// Tab, ChromeViews::ContextMenuController implementation:
-bool Tab::IsCommandEnabled(int id) const {
- return delegate_->IsCommandEnabledForTab(
- static_cast<TabStripModel::ContextMenuCommand>(id), this);
+void Tab::ShowContextMenu(ChromeViews::View* source, int x, int y,
+ bool is_mouse_gesture) {
+ TabContextMenuController controller(this);
+ controller.RunMenuAt(x, y);
}
-void Tab::ExecuteCommand(int id) {
- delegate_->ExecuteCommandForTab(
- static_cast<TabStripModel::ContextMenuCommand>(id), this);
-}
///////////////////////////////////////////////////////////////////////////////
// ChromeViews::BaseButton::ButtonListener implementation:
@@ -151,34 +226,3 @@ void Tab::ButtonPressed(ChromeViews::BaseButton* sender) {
if (sender == close_button())
delegate_->CloseTab(this);
}
-
-///////////////////////////////////////////////////////////////////////////////
-// Tab, private
-
-void Tab::RunContextMenuAt(const gfx::Point& screen_point) {
- Menu menu(this, Menu::TOPLEFT, GetViewContainer()->GetHWND());
- menu.AppendMenuItem(TabStripModel::CommandNewTab,
- l10n_util::GetString(IDS_TAB_CXMENU_NEWTAB),
- Menu::NORMAL);
- menu.AppendSeparator();
- menu.AppendMenuItem(TabStripModel::CommandReload,
- l10n_util::GetString(IDS_TAB_CXMENU_RELOAD),
- Menu::NORMAL);
- menu.AppendMenuItem(TabStripModel::CommandDuplicate,
- l10n_util::GetString(IDS_TAB_CXMENU_DUPLICATE),
- Menu::NORMAL);
- menu.AppendSeparator();
- menu.AppendMenuItem(TabStripModel::CommandCloseTab,
- l10n_util::GetString(IDS_TAB_CXMENU_CLOSETAB),
- Menu::NORMAL);
- menu.AppendMenuItem(TabStripModel::CommandCloseOtherTabs,
- l10n_util::GetString(IDS_TAB_CXMENU_CLOSEOTHERTABS),
- Menu::NORMAL);
- menu.AppendMenuItem(TabStripModel::CommandCloseTabsToRight,
- l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSTORIGHT),
- Menu::NORMAL);
- menu.AppendMenuItem(TabStripModel::CommandCloseTabsOpenedBy,
- l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSOPENEDBY),
- Menu::NORMAL);
- menu.RunMenuAt(screen_point.x(), screen_point.y());
-}
diff --git a/chrome/browser/tabs/tab.h b/chrome/browser/tabs/tab.h
index bb0a700..8c78190 100644
--- a/chrome/browser/tabs/tab.h
+++ b/chrome/browser/tabs/tab.h
@@ -50,7 +50,7 @@ class Profile;
//
///////////////////////////////////////////////////////////////////////////////
class Tab : public TabRenderer,
- public Menu::Delegate,
+ public ChromeViews::ContextMenuController,
public ChromeViews::BaseButton::ButtonListener {
public:
static const std::string kTabClassName;
@@ -77,6 +77,14 @@ class Tab : public TabRenderer,
virtual void ExecuteCommandForTab(
TabStripModel::ContextMenuCommand command_id, Tab* tab) = 0;
+ // Starts/Stops highlighting the tabs that will be affected by the
+ // specified command for the specified Tab.
+ virtual void StartHighlightTabsForCommand(
+ TabStripModel::ContextMenuCommand command_id, Tab* tab) = 0;
+ virtual void StopHighlightTabsForCommand(
+ TabStripModel::ContextMenuCommand command_id, Tab* tab) = 0;
+ virtual void StopAllHighlighting() = 0;
+
// Potentially starts a drag for the specified Tab.
virtual void MaybeStartDrag(Tab* tab,
const ChromeViews::MouseEvent& event) = 0;
@@ -92,6 +100,9 @@ class Tab : public TabRenderer,
explicit Tab(TabDelegate* delegate);
virtual ~Tab();
+ // Access the delegate.
+ TabDelegate* delegate() const { return delegate_; }
+
// Used to set/check whether this Tab is being animated closed.
void set_closing(bool closing) { closing_ = closing; }
bool closing() const { return closing_; }
@@ -111,16 +122,15 @@ class Tab : public TabRenderer,
virtual bool GetAccessibleRole(VARIANT* role);
virtual bool GetAccessibleName(std::wstring* name);
- // ChromeViews::Menu::Delegate overrides:
- virtual bool IsCommandEnabled(int id) const;
- virtual void ExecuteCommand(int id);
+ // ChromeViews::ContextMenuController overrides:
+ virtual void ShowContextMenu(ChromeViews::View* source,
+ int x,
+ int y,
+ bool is_mouse_gesture);
// ChromeViews::BaseButton::ButtonListener overrides:
virtual void ButtonPressed(ChromeViews::BaseButton* sender);
- // Run a context menu for this Tab at the specified screen point.
- void RunContextMenuAt(const gfx::Point& screen_point);
-
// An instance of a delegate object that can perform various actions based on
// user gestures.
TabDelegate* delegate_;
diff --git a/chrome/browser/tabs/tab_renderer.cc b/chrome/browser/tabs/tab_renderer.cc
index 5bfbcf0..6f7030d 100644
--- a/chrome/browser/tabs/tab_renderer.cc
+++ b/chrome/browser/tabs/tab_renderer.cc
@@ -27,6 +27,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <limits>
+
#include "chrome/browser/tabs/tab_renderer.h"
#include "base/gfx/image_operations.h"
@@ -55,6 +57,9 @@ static const int kUnselectedTitleColor = SkColorSetRGB(64, 64, 64);
// How long the hover state takes.
static const int kHoverDurationMs = 90;
+// How long the pulse throb takes.
+static const int kPulseDurationMs = 200;
+
// How opaque to make the hover state (out of 1).
static const double kHoverOpacity = 0.33;
static const double kHoverOpacityVista = 0.7;
@@ -272,6 +277,9 @@ TabRenderer::TabRenderer()
hover_animation_.reset(new SlideAnimation(this));
hover_animation_->SetSlideDuration(kHoverDurationMs);
+
+ pulse_animation_.reset(new ThrobAnimation(this));
+ pulse_animation_->SetSlideDuration(kPulseDurationMs);
}
TabRenderer::~TabRenderer() {
@@ -334,10 +342,14 @@ void TabRenderer::ValidateLoadingAnimation(AnimationState animation_state) {
SchedulePaint();
}
-void TabRenderer::AnimationProgressed(const Animation* animation) {
- if (animation == hover_animation_.get()) {
- SchedulePaint();
- }
+void TabRenderer::StartPulse() {
+ pulse_animation_->Reset();
+ pulse_animation_->StartThrobbing(std::numeric_limits<int>::max());
+}
+
+void TabRenderer::StopPulse() {
+ if (pulse_animation_->IsAnimating())
+ pulse_animation_->Stop();
}
// static
@@ -403,21 +415,7 @@ void TabRenderer::Paint(ChromeCanvas* canvas) {
show_close_button != showing_close_button_)
Layout();
- if (IsSelected()) {
- // Sometimes detaching a tab quickly can result in the model reporting it
- // as not being selected, so is_drag_clone_ ensures that we always paint
- // the active representation for the dragged tab.
- PaintActiveTabBackground(canvas);
- } else {
- // Draw our hover state.
- if (hover_animation_->GetCurrentValue() > 0) {
- PaintHoverTabBackground(canvas, hover_animation_->GetCurrentValue() *
- (win_util::ShouldUseVistaFrame() ?
- kHoverOpacityVista : kHoverOpacity));
- } else {
- PaintInactiveTabBackground(canvas);
- }
- }
+ PaintTabBackground(canvas);
// Paint the loading animation if the page is currently loading, otherwise
// show the page's favicon.
@@ -573,9 +571,48 @@ void TabRenderer::OnMouseExited(const ChromeViews::MouseEvent& e) {
hover_animation_->Hide();
}
+///////////////////////////////////////////////////////////////////////////////
+// TabRenderer, AnimationDelegate implementation:
+
+void TabRenderer::AnimationProgressed(const Animation* animation) {
+ SchedulePaint();
+}
+
+void TabRenderer::AnimationCanceled(const Animation* animation) {
+ AnimationEnded(animation);
+}
+
+void TabRenderer::AnimationEnded(const Animation* animation) {
+ SchedulePaint();
+}
+
////////////////////////////////////////////////////////////////////////////////
// TabRenderer, private
+void TabRenderer::PaintTabBackground(ChromeCanvas* canvas) {
+ if (IsSelected()) {
+ // Sometimes detaching a tab quickly can result in the model reporting it
+ // as not being selected, so is_drag_clone_ ensures that we always paint
+ // the active representation for the dragged tab.
+ PaintActiveTabBackground(canvas);
+ } else {
+ // Draw our hover state.
+ Animation* animation = NULL;
+ if (hover_animation_->IsAnimating()) {
+ animation = hover_animation_.get();
+ } else if (pulse_animation_->IsAnimating()) {
+ animation = pulse_animation_.get();
+ }
+ if (animation && animation->GetCurrentValue() > 0) {
+ PaintHoverTabBackground(canvas, animation->GetCurrentValue() *
+ (win_util::ShouldUseVistaFrame() ?
+ kHoverOpacityVista : kHoverOpacity));
+ } else {
+ PaintInactiveTabBackground(canvas);
+ }
+ }
+}
+
void TabRenderer::PaintInactiveTabBackground(ChromeCanvas* canvas) {
bool is_otr = data_.off_the_record;
canvas->DrawBitmapInt(is_otr ? *tab_inactive_otr_l : *tab_inactive_l, 0, 0);
@@ -609,7 +646,7 @@ void TabRenderer::PaintHoverTabBackground(ChromeCanvas* canvas,
canvas->DrawBitmapInt(left, 0, 0);
canvas->TileImageInt(center, tab_active_l_width, 0,
- GetWidth() - tab_active_l_width - tab_active_r_width, GetHeight());
+ GetWidth() - tab_active_l_width - tab_active_r_width, GetHeight());
canvas->DrawBitmapInt(right, GetWidth() - tab_active_r_width, 0);
}
diff --git a/chrome/browser/tabs/tab_renderer.h b/chrome/browser/tabs/tab_renderer.h
index 310a8bc..2c7ad58 100644
--- a/chrome/browser/tabs/tab_renderer.h
+++ b/chrome/browser/tabs/tab_renderer.h
@@ -33,6 +33,7 @@
#include "base/gfx/point.h"
#include "chrome/common/animation.h"
#include "chrome/common/slide_animation.h"
+#include "chrome/common/throb_animation.h"
#include "chrome/views/button.h"
#include "chrome/views/menu.h"
#include "chrome/views/view.h"
@@ -73,8 +74,9 @@ class TabRenderer : public ChromeViews::View,
// the tab isn't loading.
void ValidateLoadingAnimation(AnimationState animation_state);
- // AnimationDelegate implementation.
- virtual void AnimationProgressed(const Animation* animation);
+ // Starts/Stops a pulse animation.
+ void StartPulse();
+ void StopPulse();
// Returns the minimum possible size of a single unselected Tab.
static gfx::Size GetMinimumSize();
@@ -105,6 +107,11 @@ class TabRenderer : public ChromeViews::View,
virtual void OnMouseEntered(const ChromeViews::MouseEvent& event);
virtual void OnMouseExited(const ChromeViews::MouseEvent& event);
+ // Overridden from AnimationDelegate:
+ virtual void AnimationProgressed(const Animation* animation);
+ virtual void AnimationCanceled(const Animation* animation);
+ virtual void AnimationEnded(const Animation* animation);
+
// Starts/Stops the crash animation.
void StartCrashAnimation();
void StopCrashAnimation();
@@ -119,6 +126,7 @@ class TabRenderer : public ChromeViews::View,
void ResetCrashedFavIcon();
// Paint various portions of the Tab
+ void PaintTabBackground(ChromeCanvas* canvas);
void PaintInactiveTabBackground(ChromeCanvas* canvas);
void PaintActiveTabBackground(ChromeCanvas* canvas);
void PaintHoverTabBackground(ChromeCanvas* canvas, double opacity);
@@ -151,6 +159,9 @@ class TabRenderer : public ChromeViews::View,
// Hover animation.
scoped_ptr<SlideAnimation> hover_animation_;
+ // Pulse animation.
+ scoped_ptr<ThrobAnimation> pulse_animation_;
+
// Model data. We store this here so that we don't need to ask the underlying
// model, which is tricky since instances of this object can outlive the
// corresponding objects in the underlying model.
diff --git a/chrome/browser/tabs/tab_strip.cc b/chrome/browser/tabs/tab_strip.cc
index 327c3e5..04b33b3 100644
--- a/chrome/browser/tabs/tab_strip.cc
+++ b/chrome/browser/tabs/tab_strip.cc
@@ -890,6 +890,52 @@ void TabStrip::ExecuteCommandForTab(
model_->ExecuteContextMenuCommand(index, command_id);
}
+void TabStrip::StartHighlightTabsForCommand(
+ TabStripModel::ContextMenuCommand command_id, Tab* tab) {
+ if (command_id == TabStripModel::CommandCloseTabsOpenedBy) {
+ int index = GetIndexOfTab(tab);
+ if (index != -1) {
+ std::vector<int> indices = model_->GetIndexesOpenedBy(index);
+ std::vector<int>::const_iterator iter = indices.begin();
+ for (; iter != indices.end(); ++iter) {
+ int current_index = *iter;
+ DCHECK(current_index >= 0 && current_index < GetTabCount());
+ Tab* current_tab = GetTabAt(current_index);
+ current_tab->StartPulse();
+ }
+ }
+ } else if (command_id == TabStripModel::CommandCloseTabsToRight) {
+ int index = GetIndexOfTab(tab);
+ if (index != -1) {
+ for (int i = index + 1; i < GetTabCount(); ++i) {
+ Tab* current_tab = GetTabAt(i);
+ current_tab->StartPulse();
+ }
+ }
+ } else if (command_id == TabStripModel::CommandCloseOtherTabs) {
+ for (int i = 0; i < GetTabCount(); ++i) {
+ Tab* current_tab = GetTabAt(i);
+ if (current_tab != tab)
+ current_tab->StartPulse();
+ }
+ }
+}
+
+void TabStrip::StopHighlightTabsForCommand(
+ TabStripModel::ContextMenuCommand command_id, Tab* tab) {
+ if (command_id == TabStripModel::CommandCloseTabsOpenedBy ||
+ command_id == TabStripModel::CommandCloseTabsToRight ||
+ command_id == TabStripModel::CommandCloseOtherTabs) {
+ // Just tell all Tabs to stop pulsing - it's safe.
+ StopAllHighlighting();
+ }
+}
+
+void TabStrip::StopAllHighlighting() {
+ for (int i = 0; i < GetTabCount(); ++i)
+ GetTabAt(i)->StopPulse();
+}
+
void TabStrip::MaybeStartDrag(Tab* tab, const ChromeViews::MouseEvent& event) {
// Don't accidentally start any drag operations during animations if the
// mouse is down... during an animation tabs are being resized automatically,
diff --git a/chrome/browser/tabs/tab_strip.h b/chrome/browser/tabs/tab_strip.h
index ec1e555..ce8b95c 100644
--- a/chrome/browser/tabs/tab_strip.h
+++ b/chrome/browser/tabs/tab_strip.h
@@ -162,6 +162,11 @@ class TabStrip : public ChromeViews::View,
TabStripModel::ContextMenuCommand command_id, const Tab* tab) const;
virtual void ExecuteCommandForTab(
TabStripModel::ContextMenuCommand command_id, Tab* tab);
+ virtual void StartHighlightTabsForCommand(
+ TabStripModel::ContextMenuCommand command_id, Tab* tab);
+ virtual void StopHighlightTabsForCommand(
+ TabStripModel::ContextMenuCommand command_id, Tab* tab);
+ virtual void StopAllHighlighting();
virtual void MaybeStartDrag(Tab* tab,
const ChromeViews::MouseEvent& event);
virtual void ContinueDrag(const ChromeViews::MouseEvent& event);
diff --git a/chrome/browser/tabs/tab_strip_model.cc b/chrome/browser/tabs/tab_strip_model.cc
index 3b632fe..c71c089d 100644
--- a/chrome/browser/tabs/tab_strip_model.cc
+++ b/chrome/browser/tabs/tab_strip_model.cc
@@ -519,6 +519,16 @@ void TabStripModel::ExecuteContextMenuCommand(
}
}
+std::vector<int> TabStripModel::GetIndexesOpenedBy(int index) const {
+ std::vector<int> indices;
+ NavigationController* opener = GetTabContentsAt(index)->controller();
+ for (int i = count() - 1; i >= 0; --i) {
+ if (OpenerMatches(contents_data_.at(i), opener, true))
+ indices.push_back(i);
+ }
+ return indices;
+}
+
///////////////////////////////////////////////////////////////////////////////
// TabStripModel, NotificationObserver implementation:
diff --git a/chrome/browser/tabs/tab_strip_model.h b/chrome/browser/tabs/tab_strip_model.h
index c8e48f6..ab784d2 100644
--- a/chrome/browser/tabs/tab_strip_model.h
+++ b/chrome/browser/tabs/tab_strip_model.h
@@ -415,6 +415,10 @@ class TabStripModel : public NotificationObserver {
void ExecuteContextMenuCommand(int context_index,
ContextMenuCommand command_id);
+ // Returns a vector of indices of TabContentses opened from the TabContents
+ // at the specified |index|.
+ std::vector<int> GetIndexesOpenedBy(int index) const;
+
// Overridden from notificationObserver:
virtual void Observe(NotificationType type,
const NotificationSource& source,
diff --git a/chrome/views/chrome_menu.cc b/chrome/views/chrome_menu.cc
index 72fdf1b..271c19b 100644
--- a/chrome/views/chrome_menu.cc
+++ b/chrome/views/chrome_menu.cc
@@ -1633,6 +1633,9 @@ void MenuController::SetSelection(MenuItemView* menu_item,
for (size_t i = paths_differ_at; i < new_size; ++i)
new_path[i]->SetSelected(true);
+ if (menu_item && menu_item->GetDelegate())
+ menu_item->GetDelegate()->SelectionChanged(menu_item);
+
pending_state_.item = menu_item;
pending_state_.submenu_open = open_submenu;
diff --git a/chrome/views/chrome_menu.h b/chrome/views/chrome_menu.h
index 7a1d15b..0c478aa 100644
--- a/chrome/views/chrome_menu.h
+++ b/chrome/views/chrome_menu.h
@@ -198,6 +198,10 @@ class MenuDelegate : Controller {
// menu for a drop.
virtual void DropMenuClosed(MenuItemView* menu) {
}
+
+ // Notification that the user has highlighted the specified item.
+ virtual void SelectionChanged(MenuItemView* menu) {
+ }
};
// MenuItemView --------------------------------------------------------------