diff options
author | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-23 12:03:13 +0000 |
---|---|---|
committer | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-23 12:03:13 +0000 |
commit | fe6c81752c2e16344bfe703bce2fb3db610ecf55 (patch) | |
tree | 06a7103a1fade711e18f93d3d61b185b3b56507d | |
parent | 1bdb3530e57466f251f5c9a3f7d608b92fd7fe08 (diff) | |
download | chromium_src-fe6c81752c2e16344bfe703bce2fb3db610ecf55.zip chromium_src-fe6c81752c2e16344bfe703bce2fb3db610ecf55.tar.gz chromium_src-fe6c81752c2e16344bfe703bce2fb3db610ecf55.tar.bz2 |
Implement the confirm infobar with link for mac.
BUG=11246
TEST=browser_tests.exe --gtest_filter=Geol*
Review URL: http://codereview.chromium.org/1127001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42338 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/cocoa/infobar_controller.h | 2 | ||||
-rw-r--r-- | chrome/browser/cocoa/infobar_controller.mm | 134 | ||||
-rw-r--r-- | chrome/browser/cocoa/infobar_controller_unittest.mm | 30 | ||||
-rw-r--r-- | chrome/browser/cocoa/infobar_test_helper.h | 12 |
4 files changed, 131 insertions, 47 deletions
diff --git a/chrome/browser/cocoa/infobar_controller.h b/chrome/browser/cocoa/infobar_controller.h index b1aaaff..4d1ab4b 100644 --- a/chrome/browser/cocoa/infobar_controller.h +++ b/chrome/browser/cocoa/infobar_controller.h @@ -85,4 +85,6 @@ class InfoBarDelegate; // Called when the ok and cancel buttons are clicked. - (IBAction)ok:(id)sender; - (IBAction)cancel:(id)sender; +// Called when there is a click on the link in the infobar. +- (void)linkClicked; @end diff --git a/chrome/browser/cocoa/infobar_controller.mm b/chrome/browser/cocoa/infobar_controller.mm index 2db007e..b360041 100644 --- a/chrome/browser/cocoa/infobar_controller.mm +++ b/chrome/browser/cocoa/infobar_controller.mm @@ -36,6 +36,12 @@ const float kAnimateCloseDuration = 0.12; // Removes the ok and cancel buttons, and resizes the textfield to use the // space. - (void)removeButtons; + +// Sets the info bar message to the specified |message|, with a hypertext +// style link. |link| will be inserted into message at |link_offset|. +-(void)setLabelToMessage:(NSString*)message + withLink:(NSString*)link + atOffset:(NSUInteger)link_offset; @end @implementation InfoBarController @@ -179,6 +185,57 @@ const float kAnimateCloseDuration = 0.12; [self cleanUpAfterAnimation:YES]; } +// TODO(joth): This method factors out some common functionality between the +// various derived infobar classes, however the class hierarchy itself could +// use refactoring to reduce this duplication. http://crbug.com/38924 +-(void)setLabelToMessage:(NSString*)message + withLink:(NSString*)link + atOffset:(NSUInteger)link_offset { + // Create an attributes dictionary for the entire message. We have + // to expicitly set the font the control's font. We also override + // the cursor to give us the normal cursor rather than the text + // insertion cursor. + NSMutableDictionary* linkAttributes = + [NSMutableDictionary dictionaryWithObject:[NSCursor arrowCursor] + forKey:NSCursorAttributeName]; + [linkAttributes setObject:[label_ font] + forKey:NSFontAttributeName]; + + // Create the attributed string for the main message text. + NSMutableAttributedString* infoText = + [[[NSMutableAttributedString alloc] + initWithString:message] autorelease]; + [infoText addAttributes:linkAttributes + range:NSMakeRange(0, [infoText length])]; + + // Add additional attributes to style the link text appropriately as + // well as linkify it. We use an empty string for the NSLink + // attribute because the actual object we pass doesn't matter, but + // it cannot be nil. + [linkAttributes setObject:[NSColor blueColor] + forKey:NSForegroundColorAttributeName]; + [linkAttributes setObject:[NSNumber numberWithBool:YES] + forKey:NSUnderlineStyleAttributeName]; + [linkAttributes setObject:[NSCursor pointingHandCursor] + forKey:NSCursorAttributeName]; + [linkAttributes setObject:[NSString string] // dummy value + forKey:NSLinkAttributeName]; + + // Insert the link text into the string at the appropriate offset. + NSAttributedString* attributed_string = + [[[NSAttributedString alloc] initWithString:link + attributes:linkAttributes] autorelease]; + [infoText insertAttributedString:attributed_string + atIndex:link_offset]; + + // Update the label view with the new text. The view must be + // selectable and allow editing text attributes for the + // linkification to work correctly. + [label_ setAllowsEditingTextAttributes:YES]; + [label_ setSelectable:YES]; + [label_ setAttributedStringValue:infoText]; +} + @end @@ -224,50 +281,9 @@ const float kAnimateCloseDuration = 0.12; DCHECK(delegate); size_t offset = std::wstring::npos; std::wstring message = delegate->GetMessageTextWithOffset(&offset); - - // Create an attributes dictionary for the entire message. We have - // to expicitly set the font the control's font. We also override - // the cursor to give us the normal cursor rather than the text - // insertion cursor. - NSMutableDictionary* linkAttributes = - [NSMutableDictionary dictionaryWithObject:[NSCursor arrowCursor] - forKey:NSCursorAttributeName]; - [linkAttributes setObject:[label_ font] - forKey:NSFontAttributeName]; - - // Create the attributed string for the main message text. - NSMutableAttributedString* infoText = - [[[NSMutableAttributedString alloc] - initWithString:base::SysWideToNSString(message)] autorelease]; - [infoText addAttributes:linkAttributes - range:NSMakeRange(0, [infoText length])]; - - // Add additional attributes to style the link text appropriately as - // well as linkify it. We use an empty string for the NSLink - // attribute because the actual object we pass doesn't matter, but - // it cannot be nil. - [linkAttributes setObject:[NSColor blueColor] - forKey:NSForegroundColorAttributeName]; - [linkAttributes setObject:[NSNumber numberWithBool:YES] - forKey:NSUnderlineStyleAttributeName]; - [linkAttributes setObject:[NSCursor pointingHandCursor] - forKey:NSCursorAttributeName]; - [linkAttributes setObject:[NSString string] // dummy value - forKey:NSLinkAttributeName]; - - // Insert the link text into the string at the appropriate offset. - [infoText insertAttributedString: - [[[NSAttributedString alloc] - initWithString:base::SysWideToNSString(delegate->GetLinkText()) - attributes:linkAttributes] autorelease] - atIndex:offset]; - - // Update the label view with the new text. The view must be - // selectable and allow editing text attributes for the - // linkification to work correctly. - [label_ setAllowsEditingTextAttributes:YES]; - [label_ setSelectable:YES]; - [label_ setAttributedStringValue:infoText]; + [self setLabelToMessage:base::SysWideToNSString(message) + withLink:base::SysWideToNSString(delegate->GetLinkText()) + atOffset:offset]; } // Called when someone clicks on the link in the infobar. This method @@ -372,8 +388,34 @@ const float kAnimateCloseDuration = 0.12; frame.size.width = rightEdge - NSMinX(frame); [label_ setFrame:frame]; - // Set the text. - [label_ setStringValue:base::SysWideToNSString(delegate->GetMessageText())]; + // Set the text and link. + NSString* message = base::SysWideToNSString(delegate->GetMessageText()); + std::wstring link = delegate->GetLinkText(); + if (link.empty()) { + // Simple case: no link, so just set the message directly. + [label_ setStringValue:message]; + } else { + // Inserting the link unintentionally causes the text to have a slightly + // different result to the simple case above: text is truncated on word + // boundaries (if needed) rather than elided with ellipses. + + // Add spacing between the label and the link. + message = [message stringByAppendingString:@" "]; + [self setLabelToMessage:message + withLink:base::SysWideToNSString(link) + atOffset:[message length]]; + } +} + +// Called when someone clicks on the link in the infobar. This method +// is called by the InfobarTextField on its delegate (the +// LinkInfoBarController). +- (void)linkClicked { + WindowOpenDisposition disposition = + event_utils::WindowOpenDispositionFromNSEvent([NSApp currentEvent]); + if (delegate_ && + delegate_->AsConfirmInfoBarDelegate()->LinkClicked(disposition)) + [self removeInfoBar]; } @end diff --git a/chrome/browser/cocoa/infobar_controller_unittest.mm b/chrome/browser/cocoa/infobar_controller_unittest.mm index 6dbfb5d..5ed5f12 100644 --- a/chrome/browser/cocoa/infobar_controller_unittest.mm +++ b/chrome/browser/cocoa/infobar_controller_unittest.mm @@ -180,8 +180,9 @@ TEST_F(LinkInfoBarControllerTest, ShowAndClickLinkWithoutClosing) { TEST_VIEW(ConfirmInfoBarControllerTest, [controller_ view]); TEST_F(ConfirmInfoBarControllerTest, ShowAndDismiss) { - // Make sure someone looked at the message and icon. + // Make sure someone looked at the message, link, and icon. EXPECT_TRUE(delegate_.message_text_accessed); + EXPECT_TRUE(delegate_.link_text_accessed); EXPECT_TRUE(delegate_.icon_accessed); // Check to make sure the infobar message was set properly. @@ -192,6 +193,7 @@ TEST_F(ConfirmInfoBarControllerTest, ShowAndDismiss) { [controller_ dismiss:nil]; EXPECT_FALSE(delegate_.ok_clicked); EXPECT_FALSE(delegate_.cancel_clicked); + EXPECT_FALSE(delegate_.link_clicked); EXPECT_TRUE(delegate_.closed); } @@ -201,6 +203,7 @@ TEST_F(ConfirmInfoBarControllerTest, ShowAndClickOK) { [controller_ ok:nil]; EXPECT_TRUE(delegate_.ok_clicked); EXPECT_FALSE(delegate_.cancel_clicked); + EXPECT_FALSE(delegate_.link_clicked); EXPECT_TRUE(delegate_.closed); } @@ -212,6 +215,7 @@ TEST_F(ConfirmInfoBarControllerTest, ShowAndClickOKWithoutClosing) { [controller_ ok:nil]; EXPECT_TRUE(delegate_.ok_clicked); EXPECT_FALSE(delegate_.cancel_clicked); + EXPECT_FALSE(delegate_.link_clicked); EXPECT_FALSE(delegate_.closed); } @@ -221,6 +225,7 @@ TEST_F(ConfirmInfoBarControllerTest, ShowAndClickCancel) { [controller_ cancel:nil]; EXPECT_FALSE(delegate_.ok_clicked); EXPECT_TRUE(delegate_.cancel_clicked); + EXPECT_FALSE(delegate_.link_clicked); EXPECT_TRUE(delegate_.closed); } @@ -232,6 +237,29 @@ TEST_F(ConfirmInfoBarControllerTest, ShowAndClickCancelWithoutClosing) { [controller_ cancel:nil]; EXPECT_FALSE(delegate_.ok_clicked); EXPECT_TRUE(delegate_.cancel_clicked); + EXPECT_FALSE(delegate_.link_clicked); + EXPECT_FALSE(delegate_.closed); +} + +TEST_F(ConfirmInfoBarControllerTest, ShowAndClickLink) { + // Check that clicking on the link calls LinkClicked() on the + // delegate. It should also close the infobar. + [controller_ linkClicked]; + EXPECT_FALSE(delegate_.ok_clicked); + EXPECT_FALSE(delegate_.cancel_clicked); + EXPECT_TRUE(delegate_.link_clicked); + EXPECT_TRUE(delegate_.closed); +} + +TEST_F(ConfirmInfoBarControllerTest, ShowAndClickLinkWithoutClosing) { + delegate_.closes_on_action = false; + + // Check that clicking on the link calls LinkClicked() on the + // delegate. It should not close the infobar. + [controller_ linkClicked]; + EXPECT_FALSE(delegate_.ok_clicked); + EXPECT_FALSE(delegate_.cancel_clicked); + EXPECT_TRUE(delegate_.link_clicked); EXPECT_FALSE(delegate_.closed); } diff --git a/chrome/browser/cocoa/infobar_test_helper.h b/chrome/browser/cocoa/infobar_test_helper.h index e8f5876..7c7b84c 100644 --- a/chrome/browser/cocoa/infobar_test_helper.h +++ b/chrome/browser/cocoa/infobar_test_helper.h @@ -100,6 +100,7 @@ class MockConfirmInfoBarDelegate : public ConfirmInfoBarDelegate { icon_accessed(false), ok_clicked(false), cancel_clicked(false), + link_clicked(false), closed(false), closes_on_action(true) { } @@ -139,12 +140,23 @@ class MockConfirmInfoBarDelegate : public ConfirmInfoBarDelegate { closed = true; } + virtual std::wstring GetLinkText() { + link_text_accessed = true; + return std::wstring(); + } + + virtual bool LinkClicked(WindowOpenDisposition disposition) { + link_clicked = true; + return closes_on_action; + } + // These are declared mutable to get around const-ness issues. mutable bool message_text_accessed; mutable bool link_text_accessed; mutable bool icon_accessed; bool ok_clicked; bool cancel_clicked; + bool link_clicked; bool closed; // Determines whether the infobar closes when an action is taken or not. |