summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/cocoa/clickhold_button_cell.h17
-rw-r--r--chrome/browser/cocoa/clickhold_button_cell.mm61
-rw-r--r--chrome/browser/cocoa/clickhold_button_cell_unittest.mm62
-rw-r--r--chrome/browser/cocoa/delayedmenu_button.mm44
-rw-r--r--chrome/browser/cocoa/delayedmenu_button_unittest.mm71
-rw-r--r--chrome/chrome.gyp2
6 files changed, 221 insertions, 36 deletions
diff --git a/chrome/browser/cocoa/clickhold_button_cell.h b/chrome/browser/cocoa/clickhold_button_cell.h
index 28dde69..483336e 100644
--- a/chrome/browser/cocoa/clickhold_button_cell.h
+++ b/chrome/browser/cocoa/clickhold_button_cell.h
@@ -10,10 +10,9 @@
#include "base/scoped_nsobject.h"
#import "chrome/browser/cocoa/gradient_button_cell.h"
-// A button cell that implements "click hold" behavior after a specified
-// delay. If -setClickHoldTimeout: is never called, this behaves like a normal
-// button.
-
+// A button cell that implements "click hold" behavior after a specified delay
+// or after dragging. If click-hold is never enabled (e.g., if
+// |-setEnableClickHold:| is never called), this behaves like a normal button.
@interface ClickHoldButtonCell : GradientButtonCell {
@private
BOOL enableClickHold_;
@@ -24,16 +23,18 @@
BOOL activateOnDrag_;
}
-// Enable click-hold?
+// Enable click-hold? Default: NO.
@property(assign, nonatomic) BOOL enableClickHold;
-// Timeout is in seconds (at least 0.01, at most 3600).
+// Timeout is in seconds (at least 0.01, at most 3600). Default: 0.25 (a guess
+// at a Cocoa-ish value).
@property(assign, nonatomic) NSTimeInterval clickHoldTimeout;
-// Track only in the frame rectangle?
+// Track only in the frame rectangle? Default: NO.
@property(assign, nonatomic) BOOL trackOnlyInRect;
-// Activate (click-hold) immediately on drag?
+// Activate (click-hold) immediately on a sufficiently-large drag (if not,
+// always wait for timeout)? Default: YES.
@property(assign, nonatomic) BOOL activateOnDrag;
// Defines what to do when click-held (as per usual action/target).
diff --git a/chrome/browser/cocoa/clickhold_button_cell.mm b/chrome/browser/cocoa/clickhold_button_cell.mm
index ce39d2a..67b3df6 100644
--- a/chrome/browser/cocoa/clickhold_button_cell.mm
+++ b/chrome/browser/cocoa/clickhold_button_cell.mm
@@ -13,6 +13,12 @@ static const NSTimeInterval kMaxTimeout = 3600.0;
// Drag distance threshold to activate click-hold; should be >= 0.
static const CGFloat kDragDistThreshold = 2.5;
+// See |-resetToDefaults| (and header file) for other default values.
+
+@interface ClickHoldButtonCell (Private)
+- (void)resetToDefaults;
+@end // @interface ClickHoldButtonCell (Private)
+
@implementation ClickHoldButtonCell
// Overrides:
@@ -21,22 +27,44 @@ static const CGFloat kDragDistThreshold = 2.5;
return NO;
}
+- (id)init {
+ if ((self = [super init]))
+ [self resetToDefaults];
+ return self;
+}
+
+- (id)initWithCoder:(NSCoder*)decoder {
+ if ((self = [super initWithCoder:decoder]))
+ [self resetToDefaults];
+ return self;
+}
+
+- (id)initImageCell:(NSImage*)image {
+ if ((self = [super initImageCell:image]))
+ [self resetToDefaults];
+ return self;
+}
+
+- (id)initTextCell:(NSString*)string {
+ if ((self = [super initTextCell:string]))
+ [self resetToDefaults];
+ return self;
+}
+
- (BOOL)startTrackingAt:(NSPoint)startPoint
inView:(NSView*)controlView {
- return enableClickHold_ ?
- YES :
- [super startTrackingAt:startPoint
- inView:controlView];
+ return enableClickHold_ ? YES :
+ [super startTrackingAt:startPoint
+ inView:controlView];
}
- (BOOL)continueTracking:(NSPoint)lastPoint
at:(NSPoint)currentPoint
inView:(NSView*)controlView {
- return enableClickHold_ ?
- YES :
- [super continueTracking:lastPoint
- at:currentPoint
- inView:controlView];
+ return enableClickHold_ ? YES :
+ [super continueTracking:lastPoint
+ at:currentPoint
+ inView:controlView];
}
- (BOOL)trackMouse:(NSEvent*)originalEvent
@@ -145,3 +173,18 @@ static const CGFloat kDragDistThreshold = 2.5;
@synthesize clickHoldAction = clickHoldAction_;
@end // @implementation ClickHoldButtonCell
+
+@implementation ClickHoldButtonCell (Private)
+
+// Resets various members to defaults indicated in the header file. (Those
+// without indicated defaults are *not* touched.) Please keep the values below
+// in sync with the header file, and please be aware of side-effects on code
+// which relies on the "published" defaults.
+- (void)resetToDefaults {
+ [self setEnableClickHold:NO];
+ [self setClickHoldTimeout:0.25];
+ [self setTrackOnlyInRect:NO];
+ [self setActivateOnDrag:YES];
+}
+
+@end // @implementation ClickHoldButtonCell (Private)
diff --git a/chrome/browser/cocoa/clickhold_button_cell_unittest.mm b/chrome/browser/cocoa/clickhold_button_cell_unittest.mm
new file mode 100644
index 0000000..80edfb4
--- /dev/null
+++ b/chrome/browser/cocoa/clickhold_button_cell_unittest.mm
@@ -0,0 +1,62 @@
+// Copyright (c) 2009 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>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/cocoa/clickhold_button_cell.h"
+#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class ClickHoldButtonCellTest : public PlatformTest {
+ public:
+ ClickHoldButtonCellTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ view_.reset([[NSButton alloc] initWithFrame:frame]);
+ scoped_nsobject<ClickHoldButtonCell> cell(
+ [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
+ [view_ setCell:cell.get()];
+ [cocoa_helper_.contentView() addSubview:view_.get()];
+ }
+
+ CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc.
+ scoped_nsobject<NSButton> view_;
+};
+
+// Test adding/removing from the view hierarchy, mostly to ensure nothing leaks
+// or crashes.
+TEST_F(ClickHoldButtonCellTest, AddRemove) {
+ EXPECT_EQ(cocoa_helper_.contentView(), [view_ superview]);
+ [view_.get() removeFromSuperview];
+ EXPECT_FALSE([view_ superview]);
+}
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(ClickHoldButtonCellTest, Display) {
+ [view_ display];
+}
+
+// Test default values; make sure they are what they should be.
+TEST_F(ClickHoldButtonCellTest, Defaults) {
+ ClickHoldButtonCell* cell = static_cast<ClickHoldButtonCell*>([view_ cell]);
+ ASSERT_TRUE([cell isKindOfClass:[ClickHoldButtonCell class]]);
+
+ EXPECT_FALSE([cell enableClickHold]);
+
+ NSTimeInterval clickHoldTimeout = [cell clickHoldTimeout];
+ EXPECT_GE(clickHoldTimeout, 0.15); // Check for a "Cocoa-ish" value.
+ EXPECT_LE(clickHoldTimeout, 0.35);
+
+ EXPECT_FALSE([cell trackOnlyInRect]);
+ EXPECT_TRUE([cell activateOnDrag]);
+}
+
+// TODO(viettrungluu): (1) Enable click-hold and figure out how to test the
+// tracking loop (i.e., |-trackMouse:...|), which is the nontrivial part.
+// (2) Test various initialization code paths (in particular, loading from nib).
+
+} // namespace
diff --git a/chrome/browser/cocoa/delayedmenu_button.mm b/chrome/browser/cocoa/delayedmenu_button.mm
index 5269730..2be6928 100644
--- a/chrome/browser/cocoa/delayedmenu_button.mm
+++ b/chrome/browser/cocoa/delayedmenu_button.mm
@@ -10,7 +10,7 @@
@interface DelayedMenuButton (Private)
-- (void)resetToDefaults;
+- (void)setupCell;
- (void)menuAction:(id)sender;
@end // @interface DelayedMenuButton (Private)
@@ -25,19 +25,19 @@
- (id)init {
if ((self = [super init]))
- [self resetToDefaults];
+ [self setupCell];
return self;
}
- (id)initWithCoder:(NSCoder*)decoder {
if ((self = [super initWithCoder:decoder]))
- [self resetToDefaults];
+ [self setupCell];
return self;
}
- (id)initWithFrame:(NSRect)frameRect {
if ((self = [super initWithFrame:frameRect]))
- [self resetToDefaults];
+ [self setupCell];
return self;
}
@@ -47,7 +47,12 @@
}
- (void)awakeFromNib {
- [self resetToDefaults];
+ [self setupCell];
+}
+
+- (void)setCell:(NSCell*)cell {
+ [super setCell:cell];
+ [self setupCell];
}
// Accessors and mutators:
@@ -68,19 +73,20 @@
@implementation DelayedMenuButton (Private)
-- (void)resetToDefaults {
- id cell = [self cell];
- DCHECK([cell isKindOfClass:[ClickHoldButtonCell class]]);
- [self setEnabled:NO]; // Make the controller put in a menu and
+// Set up the button's cell if we've reached a point where it's been set.
+- (void)setupCell {
+ ClickHoldButtonCell* cell = [self cell];
+ if (cell) {
+ DCHECK([cell isKindOfClass:[ClickHoldButtonCell class]]);
+ [self setEnabled:NO]; // Make the controller put in a menu and
// enable it explicitly. This also takes
// care of |[cell setEnableClickHold:]|.
- [cell setClickHoldTimeout:0.25]; // Random guess at Cocoa-ish value.
- [cell setTrackOnlyInRect:NO];
- [cell setActivateOnDrag:YES];
- [cell setClickHoldAction:@selector(menuAction:)];
- [cell setClickHoldTarget:self];
+ [cell setClickHoldAction:@selector(menuAction:)];
+ [cell setClickHoldTarget:self];
+ }
}
+// Display the menu.
- (void)menuAction:(id)sender {
// We shouldn't get here unless the menu is enabled.
DCHECK(menuEnabled_);
@@ -96,11 +102,11 @@
return;
}
- // FIXME(viettrungluu@gmail.com): We have some fudge factors below to make
- // things line up (approximately). I wish I knew how to get rid of them. (Note
- // that our view is flipped, and that frame should be in our coordinates.)
- // The y/height is very odd, since it doesn't seem to respond to changes the
- // way that it should. I don't understand it.
+ // FIXME(viettrungluu): We have some fudge factors below to make things line
+ // up (approximately). I wish I knew how to get rid of them. (Note that our
+ // view is flipped, and that frame should be in our coordinates.) The y/height
+ // is very odd, since it doesn't seem to respond to changes the way that it
+ // should. I don't understand it.
NSRect frame = [self convertRect:[self frame]
fromView:[self superview]];
frame.origin.x -= 2.0;
diff --git a/chrome/browser/cocoa/delayedmenu_button_unittest.mm b/chrome/browser/cocoa/delayedmenu_button_unittest.mm
new file mode 100644
index 0000000..b04cb27
--- /dev/null
+++ b/chrome/browser/cocoa/delayedmenu_button_unittest.mm
@@ -0,0 +1,71 @@
+// Copyright (c) 2009 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>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/cocoa/clickhold_button_cell.h"
+#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#import "chrome/browser/cocoa/delayedmenu_button.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class DelayedMenuButtonTest : public PlatformTest {
+ public:
+ DelayedMenuButtonTest() {
+ NSRect frame = NSMakeRect(0, 0, 50, 30);
+ button_.reset([[DelayedMenuButton alloc] initWithFrame:frame]);
+ scoped_nsobject<ClickHoldButtonCell> cell(
+ [[ClickHoldButtonCell alloc] initTextCell:@"Testing"]);
+ [button_ setCell:cell.get()];
+ [cocoa_helper_.contentView() addSubview:button_.get()];
+ }
+
+ scoped_nsobject<DelayedMenuButton> button_;
+ CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc.
+};
+
+// Test adding/removing from the view hierarchy, mostly to ensure nothing leaks
+// or crashes.
+TEST_F(DelayedMenuButtonTest, AddRemove) {
+ EXPECT_EQ(cocoa_helper_.contentView(), [button_ superview]);
+ [button_.get() removeFromSuperview];
+ EXPECT_FALSE([button_ superview]);
+}
+
+// Test drawing, mostly to ensure nothing leaks or crashes.
+TEST_F(DelayedMenuButtonTest, Display) {
+ [button_ display];
+}
+
+// Test assigning and enabling a menu, again mostly to ensure nothing leaks or
+// crashes.
+TEST_F(DelayedMenuButtonTest, MenuAssign) {
+ scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@""]);
+ ASSERT_TRUE(menu.get());
+
+ [menu insertItemWithTitle:@"" action:nil keyEquivalent:@"" atIndex:0];
+ [menu insertItemWithTitle:@"foo" action:nil keyEquivalent:@"" atIndex:1];
+ [menu insertItemWithTitle:@"bar" action:nil keyEquivalent:@"" atIndex:2];
+ [menu insertItemWithTitle:@"baz" action:nil keyEquivalent:@"" atIndex:3];
+
+ [button_ setMenu:menu];
+ EXPECT_TRUE([button_ menu]);
+
+ [button_ setMenuEnabled:YES];
+ EXPECT_TRUE([button_ menuEnabled]);
+
+ // TODO(viettrungluu): Display the menu. (Calling DelayedMenuButton's private
+ // |-menuAction:| method displays it fine, but the problem is getting rid of
+ // the menu. We can catch the |NSMenuDidBeginTrackingNotification| from |menu|
+ // fine, but then |-cancelTracking| doesn't dismiss it. I don't know why.)
+}
+
+// TODO(viettrungluu): Test the two actions of the button (the normal one and
+// displaying the menu, also making sure the latter drags correctly)? It would
+// require "emulating" a mouse....
+
+} // namespace
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index b2becc4..e4bbe6f 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -3972,8 +3972,10 @@
'browser/cocoa/browser_window_cocoa_unittest.mm',
'browser/cocoa/browser_window_controller_unittest.mm',
'browser/cocoa/clear_browsing_data_controller_unittest.mm',
+ 'browser/cocoa/clickhold_button_cell_unittest.mm',
'browser/cocoa/command_observer_bridge_unittest.mm',
'browser/cocoa/custom_home_pages_model_unittest.mm',
+ 'browser/cocoa/delayedmenu_button_unittest.mm',
'browser/cocoa/download_shelf_mac_unittest.mm',
'browser/cocoa/download_shelf_view_unittest.mm',
'browser/cocoa/download_util_mac_unittest.mm',