summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/nibs/Toolbar.xib14
-rw-r--r--chrome/browser/cocoa/browser_window_cocoa.mm2
-rw-r--r--chrome/browser/cocoa/browser_window_controller.h4
-rw-r--r--chrome/browser/cocoa/browser_window_controller.mm4
-rw-r--r--chrome/browser/cocoa/gradient_button_cell.h6
-rw-r--r--chrome/browser/cocoa/reload_button.h44
-rw-r--r--chrome/browser/cocoa/reload_button.mm116
-rw-r--r--chrome/browser/cocoa/reload_button_unittest.mm187
-rw-r--r--chrome/browser/cocoa/test_event_utils.h8
-rw-r--r--chrome/browser/cocoa/test_event_utils.mm24
-rw-r--r--chrome/browser/cocoa/toolbar_controller.h11
-rw-r--r--chrome/browser/cocoa/toolbar_controller.mm13
-rw-r--r--chrome/browser/cocoa/toolbar_controller_unittest.mm4
-rw-r--r--chrome/chrome_browser.gypi6
-rw-r--r--chrome/chrome_tests.gypi1
15 files changed, 413 insertions, 31 deletions
diff --git a/chrome/app/nibs/Toolbar.xib b/chrome/app/nibs/Toolbar.xib
index 912ba7c..7cfe603 100644
--- a/chrome/app/nibs/Toolbar.xib
+++ b/chrome/app/nibs/Toolbar.xib
@@ -510,6 +510,7 @@
<string>2.CustomClassName</string>
<string>2.IBAttributePlaceholdersKey</string>
<string>2.IBPluginDependency</string>
+ <string>3.CustomClassName</string>
<string>3.IBAttributePlaceholdersKey</string>
<string>3.IBPluginDependency</string>
<string>38.CustomClassName</string>
@@ -532,7 +533,7 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{370, 714}, {616, 36}}</string>
+ <string>{{319, 714}, {616, 36}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<boolean value="YES"/>
<string>ClickHoldButtonCell</string>
@@ -556,6 +557,7 @@
</object>
</object>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>ReloadButton</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
@@ -780,6 +782,14 @@
</object>
</object>
<object class="IBPartialClassDescription">
+ <string key="className">ReloadButton</string>
+ <string key="superclassName">NSButton</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/reload_button_mac.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
<string key="className">StyledTextField</string>
<string key="superclassName">NSTextField</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
@@ -818,7 +828,7 @@
<string>DelayedMenuButton</string>
<string>NSButton</string>
<string>AutocompleteTextField</string>
- <string>NSButton</string>
+ <string>ReloadButton</string>
<string>id</string>
<string>MenuButton</string>
</object>
diff --git a/chrome/browser/cocoa/browser_window_cocoa.mm b/chrome/browser/cocoa/browser_window_cocoa.mm
index 556263b..274f5b8 100644
--- a/chrome/browser/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/cocoa/browser_window_cocoa.mm
@@ -219,7 +219,7 @@ void BrowserWindowCocoa::SetFocusToLocationBar(bool select_all) {
}
void BrowserWindowCocoa::UpdateReloadStopState(bool is_loading, bool force) {
- [controller_ setIsLoading:is_loading ? YES : NO];
+ [controller_ setIsLoading:is_loading force:force];
}
void BrowserWindowCocoa::UpdateToolbar(TabContents* contents,
diff --git a/chrome/browser/cocoa/browser_window_controller.h b/chrome/browser/cocoa/browser_window_controller.h
index aaf843a..5882363 100644
--- a/chrome/browser/cocoa/browser_window_controller.h
+++ b/chrome/browser/cocoa/browser_window_controller.h
@@ -175,7 +175,9 @@ class TabStripModelObserverBridge;
- (NSRect)selectedTabGrowBoxRect;
// Called to tell the selected tab to update its loading state.
-- (void)setIsLoading:(BOOL)isLoading;
+// |force| is set if the update is due to changing tabs, as opposed to
+// the page-load finishing. See comment in reload_button.h.
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force;
// Brings this controller's window to the front.
- (void)activate;
diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm
index 96b0245..aa7b325 100644
--- a/chrome/browser/cocoa/browser_window_controller.mm
+++ b/chrome/browser/cocoa/browser_window_controller.mm
@@ -1104,8 +1104,8 @@
return [tabStripController_ selectedTabView];
}
-- (void)setIsLoading:(BOOL)isLoading {
- [toolbarController_ setIsLoading:isLoading];
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
+ [toolbarController_ setIsLoading:isLoading force:force];
}
// Make the location bar the first responder, if possible.
diff --git a/chrome/browser/cocoa/gradient_button_cell.h b/chrome/browser/cocoa/gradient_button_cell.h
index 72b3c30..44ce2c1 100644
--- a/chrome/browser/cocoa/gradient_button_cell.h
+++ b/chrome/browser/cocoa/gradient_button_cell.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_COCOA_CHROMIUM_BUTTON_CELL_H_
-#define CHROME_BROWSER_COCOA_CHROMIUM_BUTTON_CELL_H_
+#ifndef CHROME_BROWSER_COCOA_GRADIENT_BUTTON_CELL_H_
+#define CHROME_BROWSER_COCOA_GRADIENT_BUTTON_CELL_H_
#import <Cocoa/Cocoa.h>
@@ -73,4 +73,4 @@ typedef NSInteger ButtonType;
- (BOOL)isMouseInside;
@end
-#endif // CHROME_BROWSER_COCOA_CHROMIUM_BUTTON_CELL_H_
+#endif // CHROME_BROWSER_COCOA_GRADIENT_BUTTON_CELL_H_
diff --git a/chrome/browser/cocoa/reload_button.h b/chrome/browser/cocoa/reload_button.h
new file mode 100644
index 0000000..c26f047
--- /dev/null
+++ b/chrome/browser/cocoa/reload_button.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_COCOA_RELOAD_BUTTON_H_
+#define CHROME_BROWSER_COCOA_RELOAD_BUTTON_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/scoped_nsobject.h"
+
+// NSButton subclass which defers certain state changes when the mouse
+// is hovering over it.
+
+@interface ReloadButton : NSButton {
+ @private
+ // Tracks whether the mouse is hovering for purposes of not making
+ // unexpected state changes.
+ BOOL isMouseInside_;
+ scoped_nsobject<NSTrackingArea> trackingArea_;
+
+ // Set when reload mode is requested, but not forced, and the mouse
+ // is hovering.
+ BOOL pendingReloadMode_;
+}
+
+// Returns YES if the mouse is currently inside the bounds.
+- (BOOL)isMouseInside;
+
+// Update the button to be a reload button or stop button depending on
+// |isLoading|. If |force|, always sets the indicated mode. If
+// |!force|, and the mouse is over the button, defer the transition
+// from stop button to reload button until the mouse has left the
+// button. This prevents an inadvertent click _just_ as the state
+// changes.
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force;
+
+@end
+
+@interface ReloadButton (PrivateTestingMethods)
+- (NSTrackingArea*)trackingArea;
+@end
+
+#endif // CHROME_BROWSER_COCOA_RELOAD_BUTTON_H_
diff --git a/chrome/browser/cocoa/reload_button.mm b/chrome/browser/cocoa/reload_button.mm
new file mode 100644
index 0000000..53e6c58
--- /dev/null
+++ b/chrome/browser/cocoa/reload_button.mm
@@ -0,0 +1,116 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/cocoa/reload_button.h"
+
+#include "base/nsimage_cache_mac.h"
+#include "chrome/app/chrome_dll_resource.h"
+
+namespace {
+
+NSString* const kReloadImageName = @"reload_Template.pdf";
+NSString* const kStopImageName = @"stop_Template.pdf";
+
+} // namespace
+
+@implementation ReloadButton
+
+- (void)dealloc {
+ if (trackingArea_) {
+ [self removeTrackingArea:trackingArea_];
+ trackingArea_.reset();
+ }
+ [super dealloc];
+}
+
+- (void)updateTrackingAreas {
+ // If the mouse is hovering when the tracking area is updated, the
+ // control could end up locked into inappropriate behavior for
+ // awhile, so unwind state.
+ if (isMouseInside_)
+ [self mouseExited:nil];
+
+ if (trackingArea_) {
+ [self removeTrackingArea:trackingArea_];
+ trackingArea_.reset();
+ }
+ trackingArea_.reset([[NSTrackingArea alloc]
+ initWithRect:[self bounds]
+ options:(NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveInActiveApp)
+ owner:self
+ userInfo:nil]);
+ [self addTrackingArea:trackingArea_];
+}
+
+- (void)awakeFromNib {
+ [self updateTrackingAreas];
+
+ // Don't allow multi-clicks, because the user probably wouldn't ever
+ // want to stop+reload or reload+stop.
+ [self setIgnoresMultiClick:YES];
+}
+
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
+ pendingReloadMode_ = NO;
+
+ // Can always transition to stop mode. Only transition to reload
+ // mode if forced or if the mouse isn't hovering. Otherwise, note
+ // that reload mode is desired and make no change.
+ if (isLoading) {
+ [self setImage:nsimage_cache::ImageNamed(kStopImageName)];
+ [self setTag:IDC_STOP];
+ } else if (force || ![self isMouseInside]) {
+ [self setImage:nsimage_cache::ImageNamed(kReloadImageName)];
+ [self setTag:IDC_RELOAD];
+ } else if ([self tag] == IDC_STOP) {
+ pendingReloadMode_ = YES;
+ }
+}
+
+- (BOOL)sendAction:(SEL)theAction to:(id)theTarget {
+ if ([self tag] == IDC_STOP) {
+ // The stop command won't be valid after the attempt to change
+ // back to reload. But it "worked", so short-circuit it.
+ const BOOL ret =
+ pendingReloadMode_ ? YES : [super sendAction:theAction to:theTarget];
+
+ // When the stop is processed, immediately change to reload mode,
+ // even though the IPC still has to bounce off the renderer and
+ // back before the regular |-setIsLoaded:force:| will be called.
+ // [This is how views and gtk do it.]
+ if (ret)
+ [self setIsLoading:NO force:YES];
+
+ return ret;
+ }
+
+ return [super sendAction:theAction to:theTarget];
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent {
+ isMouseInside_ = YES;
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+ isMouseInside_ = NO;
+
+ // Reload mode was requested during the hover.
+ if (pendingReloadMode_)
+ [self setIsLoading:NO force:YES];
+}
+
+- (BOOL)isMouseInside {
+ return trackingArea_ && isMouseInside_;
+}
+
+@end // ReloadButton
+
+@implementation ReloadButton (Testing)
+
+- (NSTrackingArea*)trackingArea {
+ return trackingArea_;
+}
+
+@end
diff --git a/chrome/browser/cocoa/reload_button_unittest.mm b/chrome/browser/cocoa/reload_button_unittest.mm
new file mode 100644
index 0000000..64deb96
--- /dev/null
+++ b/chrome/browser/cocoa/reload_button_unittest.mm
@@ -0,0 +1,187 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/cocoa/reload_button.h"
+
+#include "base/scoped_nsobject.h"
+#include "chrome/app/chrome_dll_resource.h"
+#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/cocoa/test_event_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+@protocol TargetActionMock <NSObject>
+- (void)anAction:(id)sender;
+@end
+
+namespace {
+
+class ReloadButtonTest : public CocoaTest {
+ public:
+ ReloadButtonTest() {
+ NSRect frame = NSMakeRect(0, 0, 20, 20);
+ scoped_nsobject<ReloadButton> button(
+ [[ReloadButton alloc] initWithFrame:frame]);
+ button_ = button.get();
+
+ // Set things up so unit tests have a reliable baseline.
+ [button_ setTag:IDC_RELOAD];
+ [button_ awakeFromNib];
+
+ [[test_window() contentView] addSubview:button_];
+ }
+
+ ReloadButton* button_;
+};
+
+TEST_VIEW(ReloadButtonTest, button_)
+
+// Test that mouse-tracking is setup and does the right thing.
+TEST_F(ReloadButtonTest, IsMouseInside) {
+ EXPECT_TRUE([[button_ trackingAreas] containsObject:[button_ trackingArea]]);
+
+ EXPECT_FALSE([button_ isMouseInside]);
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ mouseExited:nil];
+}
+
+// Verify that multiple clicks do not result in multiple messages to
+// the target.
+TEST_F(ReloadButtonTest, IgnoredMultiClick) {
+ id mock_target = [OCMockObject mockForProtocol:@protocol(TargetActionMock)];
+ [button_ setTarget:mock_target];
+ [button_ setAction:@selector(anAction:)];
+
+ // Expect the action once.
+ [[mock_target expect] anAction:button_];
+
+ const std::pair<NSEvent*,NSEvent*> click_one =
+ test_event_utils::MouseClickInView(button_, 1);
+ const std::pair<NSEvent*,NSEvent*> click_two =
+ test_event_utils::MouseClickInView(button_, 2);
+ [NSApp postEvent:click_one.second atStart:YES];
+ [button_ mouseDown:click_one.first];
+ [NSApp postEvent:click_two.second atStart:YES];
+ [button_ mouseDown:click_two.first];
+
+ [button_ setTarget:nil];
+}
+
+// Test that when forcing the mode, it takes effect immediately,
+// regardless of whether the mouse is hovering.
+TEST_F(ReloadButtonTest, SetIsLoadingForce) {
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ([button_ tag], IDC_RELOAD);
+
+ // Changes to stop immediately.
+ [button_ setIsLoading:YES force:YES];
+ EXPECT_EQ([button_ tag], IDC_STOP);
+
+ // Changes to reload immediately.
+ [button_ setIsLoading:NO force:YES];
+ EXPECT_EQ([button_ tag], IDC_RELOAD);
+
+ // Changes to stop immediately when the mouse is hovered, and
+ // doesn't change when the mouse exits.
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:YES force:YES];
+ EXPECT_EQ([button_ tag], IDC_STOP);
+ [button_ mouseExited:nil];
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ([button_ tag], IDC_STOP);
+
+ // Changes to reload immediately when the mouse is hovered, and
+ // doesn't change when the mouse exits.
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:NO force:YES];
+ EXPECT_EQ([button_ tag], IDC_RELOAD);
+ [button_ mouseExited:nil];
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ([button_ tag], IDC_RELOAD);
+}
+
+// Test that without force, stop mode is set immediately, but reload
+// is affected by the hover status.
+TEST_F(ReloadButtonTest, SetIsLoadingNoForce) {
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ([button_ tag], IDC_RELOAD);
+
+ // Changes to stop immediately when the mouse is not hovering.
+ [button_ setIsLoading:YES force:NO];
+ EXPECT_EQ([button_ tag], IDC_STOP);
+
+ // Changes to reload immediately when the mouse is not hovering.
+ [button_ setIsLoading:NO force:NO];
+ EXPECT_EQ([button_ tag], IDC_RELOAD);
+
+ // Changes to stop immediately when the mouse is hovered, and
+ // doesn't change when the mouse exits.
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:YES force:NO];
+ EXPECT_EQ([button_ tag], IDC_STOP);
+ [button_ mouseExited:nil];
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ([button_ tag], IDC_STOP);
+
+ // Does not change to reload immediately when the mouse is hovered,
+ // changes when the mouse exits.
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:NO force:NO];
+ EXPECT_EQ([button_ tag], IDC_STOP);
+ [button_ mouseExited:nil];
+ EXPECT_FALSE([button_ isMouseInside]);
+ EXPECT_EQ([button_ tag], IDC_RELOAD);
+}
+
+// Test that pressing stop after reload mode has been requested
+// doesn't forward the stop message.
+TEST_F(ReloadButtonTest, StopAfterReloadSet) {
+ id mock_target = [OCMockObject mockForProtocol:@protocol(TargetActionMock)];
+ [button_ setTarget:mock_target];
+ [button_ setAction:@selector(anAction:)];
+
+ EXPECT_FALSE([button_ isMouseInside]);
+
+ // Get to stop mode.
+ [button_ setIsLoading:YES force:YES];
+ EXPECT_EQ([button_ tag], IDC_STOP);
+
+ // Expect the action once.
+ [[mock_target expect] anAction:button_];
+
+ // Clicking in stop mode should send the action and transition to
+ // reload mode.
+ const std::pair<NSEvent*,NSEvent*> click =
+ test_event_utils::MouseClickInView(button_, 1);
+ [NSApp postEvent:click.second atStart:YES];
+ [button_ mouseDown:click.first];
+ EXPECT_EQ([button_ tag], IDC_RELOAD);
+
+ // Get back to stop mode.
+ [button_ setIsLoading:YES force:YES];
+ EXPECT_EQ([button_ tag], IDC_STOP);
+
+ // If hover prevented reload mode immediately taking effect, clicks
+ // should not send any action, but should still transition to reload
+ // mode.
+ [button_ mouseEntered:nil];
+ EXPECT_TRUE([button_ isMouseInside]);
+ [button_ setIsLoading:NO force:NO];
+ EXPECT_EQ([button_ tag], IDC_STOP);
+ [NSApp postEvent:click.second atStart:YES];
+ [button_ mouseDown:click.first];
+ EXPECT_EQ([button_ tag], IDC_RELOAD);
+
+ [button_ setTarget:nil];
+}
+
+} // namespace
diff --git a/chrome/browser/cocoa/test_event_utils.h b/chrome/browser/cocoa/test_event_utils.h
index 6b2eba5..f81fc6c 100644
--- a/chrome/browser/cocoa/test_event_utils.h
+++ b/chrome/browser/cocoa/test_event_utils.h
@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_COCOA_TEST_EVENT_UTILS_H_
#define CHROME_BROWSER_COCOA_TEST_EVENT_UTILS_H_
+#include <utility>
+
#import <objc/objc-class.h>
#include "base/logging.h"
@@ -35,7 +37,11 @@ NSEvent* MouseEventAtPoint(NSPoint point, NSEventType type,
NSEvent* LeftMouseDownAtPoint(NSPoint point);
NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window);
+// Return a mouse down and an up event with the given |clickCount| at
+// |view|'s midpoint.
+std::pair<NSEvent*,NSEvent*> MouseClickInView(NSView* view,
+ NSUInteger clickCount);
+
} // namespace test_event_utils
#endif // CHROME_BROWSER_COCOA_TEST_EVENT_UTILS_H_
-
diff --git a/chrome/browser/cocoa/test_event_utils.mm b/chrome/browser/cocoa/test_event_utils.mm
index 23b0535..8016111 100644
--- a/chrome/browser/cocoa/test_event_utils.mm
+++ b/chrome/browser/cocoa/test_event_utils.mm
@@ -49,20 +49,38 @@ NSEvent* MakeMouseEvent(NSEventType type, NSUInteger modifiers) {
return MouseEventAtPoint(NSMakePoint(0, 0), type, modifiers);
}
-NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window) {
- return [NSEvent mouseEventWithType:NSLeftMouseDown
+static NSEvent* MouseEventAtPointInWindow(NSPoint point,
+ NSEventType type,
+ NSWindow* window,
+ NSUInteger clickCount) {
+ return [NSEvent mouseEventWithType:type
location:point
modifierFlags:0
timestamp:0
windowNumber:[window windowNumber]
context:nil
eventNumber:0
- clickCount:1
+ clickCount:clickCount
pressure:1.0];
}
+NSEvent* LeftMouseDownAtPointInWindow(NSPoint point, NSWindow* window) {
+ return MouseEventAtPointInWindow(point, NSLeftMouseDown, window, 1);
+}
+
NSEvent* LeftMouseDownAtPoint(NSPoint point) {
return LeftMouseDownAtPointInWindow(point, nil);
}
+std::pair<NSEvent*,NSEvent*> MouseClickInView(NSView* view,
+ NSUInteger clickCount) {
+ const NSRect bounds = [view convertRect:[view bounds] toView:nil];
+ const NSPoint mid_point = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
+ NSEvent* down = MouseEventAtPointInWindow(mid_point, NSLeftMouseDown,
+ [view window], clickCount);
+ NSEvent* up = MouseEventAtPointInWindow(mid_point, NSLeftMouseUp,
+ [view window], clickCount);
+ return std::make_pair(down, up);
+}
+
} // namespace test_event_utils
diff --git a/chrome/browser/cocoa/toolbar_controller.h b/chrome/browser/cocoa/toolbar_controller.h
index 313ef4e..be27c42 100644
--- a/chrome/browser/cocoa/toolbar_controller.h
+++ b/chrome/browser/cocoa/toolbar_controller.h
@@ -32,6 +32,7 @@ class MenuDelegate;
class PrefObserverBridge;
}
class Profile;
+@class ReloadButton;
class TabContents;
class ToolbarModel;
class WrenchMenuModel;
@@ -49,7 +50,7 @@ class WrenchMenuModel;
// corresponding enum in the unit tests.
IBOutlet DelayedMenuButton* backButton_;
IBOutlet DelayedMenuButton* forwardButton_;
- IBOutlet NSButton* reloadButton_;
+ IBOutlet ReloadButton* reloadButton_;
IBOutlet NSButton* homeButton_;
IBOutlet MenuButton* wrenchButton_;
IBOutlet AutocompleteTextField* locationBar_;
@@ -129,9 +130,11 @@ class WrenchMenuModel;
// Sets whether or not the current page in the frontmost tab is bookmarked.
- (void)setStarredState:(BOOL)isStarred;
-// Called to update the loading state. Handles updating the go/stop button
-// state.
-- (void)setIsLoading:(BOOL)isLoading;
+// Called to update the loading state. Handles updating the go/stop
+// button state. |force| is set if the update is due to changing
+// tabs, as opposed to the page-load finishing. See comment in
+// reload_button.h.
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force;
// Allow turning off the toolbar (but we may keep the location bar without a
// surrounding toolbar). If |toolbar| is YES, the value of |hasLocationBar| is
diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm
index 4823f31..7487241 100644
--- a/chrome/browser/cocoa/toolbar_controller.mm
+++ b/chrome/browser/cocoa/toolbar_controller.mm
@@ -29,6 +29,7 @@
#import "chrome/browser/cocoa/location_bar/location_bar_view_mac.h"
#import "chrome/browser/cocoa/menu_button.h"
#import "chrome/browser/cocoa/menu_controller.h"
+#import "chrome/browser/cocoa/reload_button.h"
#import "chrome/browser/cocoa/toolbar_view.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/pref_service.h"
@@ -412,16 +413,8 @@ class PrefObserverBridge : public NotificationObserver {
locationBarView_->SetStarred(isStarred ? true : false);
}
-- (void)setIsLoading:(BOOL)isLoading {
- NSString* imageName = kReloadButtonReloadImageName;
- NSInteger tag = IDC_RELOAD;
- if (isLoading) {
- imageName = kReloadButtonStopImageName;
- tag = IDC_STOP;
- }
- NSImage* stopStartImage = nsimage_cache::ImageNamed(imageName);
- [reloadButton_ setImage:stopStartImage];
- [reloadButton_ setTag:tag];
+- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
+ [reloadButton_ setIsLoading:isLoading force:force];
}
- (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar {
diff --git a/chrome/browser/cocoa/toolbar_controller_unittest.mm b/chrome/browser/cocoa/toolbar_controller_unittest.mm
index b601e69..c5f155d 100644
--- a/chrome/browser/cocoa/toolbar_controller_unittest.mm
+++ b/chrome/browser/cocoa/toolbar_controller_unittest.mm
@@ -154,9 +154,9 @@ TEST_F(ToolbarControllerTest, LoadingState) {
// IDC_RELOAD. When loading, it should be IDC_STOP.
NSButton* reload = [[bar_ toolbarViews] objectAtIndex:kReloadIndex];
EXPECT_EQ([reload tag], IDC_RELOAD);
- [bar_ setIsLoading:YES];
+ [bar_ setIsLoading:YES force:YES];
EXPECT_EQ([reload tag], IDC_STOP);
- [bar_ setIsLoading:NO];
+ [bar_ setIsLoading:NO force:YES];
EXPECT_EQ([reload tag], IDC_RELOAD);
}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index bdbad71..7ff5c45 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -855,12 +855,14 @@
'browser/cocoa/page_info_window_mac.mm',
'browser/cocoa/preferences_window_controller.h',
'browser/cocoa/preferences_window_controller.mm',
- 'browser/cocoa/rwhvm_editcommand_helper.h',
- 'browser/cocoa/rwhvm_editcommand_helper.mm',
+ 'browser/cocoa/reload_button.h',
+ 'browser/cocoa/reload_button.mm',
'browser/cocoa/repost_form_warning_mac.h',
'browser/cocoa/repost_form_warning_mac.mm',
'browser/cocoa/restart_browser.h',
'browser/cocoa/restart_browser.mm',
+ 'browser/cocoa/rwhvm_editcommand_helper.h',
+ 'browser/cocoa/rwhvm_editcommand_helper.mm',
'browser/cocoa/sad_tab_controller.h',
'browser/cocoa/sad_tab_controller.mm',
'browser/cocoa/sad_tab_view.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index e5d9f8e..cd9101e 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -748,6 +748,7 @@
'browser/cocoa/objc_method_swizzle_unittest.mm',
'browser/cocoa/page_info_window_mac_unittest.mm',
'browser/cocoa/preferences_window_controller_unittest.mm',
+ 'browser/cocoa/reload_button_unittest.mm',
'browser/cocoa/rwhvm_editcommand_helper_unittest.mm',
'browser/cocoa/sad_tab_controller_unittest.mm',
'browser/cocoa/sad_tab_view_unittest.mm',