diff options
Diffstat (limited to 'chrome/browser/cocoa')
19 files changed, 938 insertions, 577 deletions
diff --git a/chrome/browser/cocoa/autocomplete_text_field.h b/chrome/browser/cocoa/autocomplete_text_field.h index 1b1856d..8e16705 100644 --- a/chrome/browser/cocoa/autocomplete_text_field.h +++ b/chrome/browser/cocoa/autocomplete_text_field.h @@ -119,6 +119,13 @@ class AutocompleteTextFieldObserver { // is not over an action. - (NSMenu*)actionMenuForEvent:(NSEvent*)event; +// Return the rectangle the star is being shown in, for purposes of +// positioning the bookmark bubble. +- (NSRect)starIconFrame; + +// If the location icon is draggable, return its drag pasteboard. +- (NSPasteboard*)locationDragPasteboard; + @end #endif // CHROME_BROWSER_COCOA_AUTOCOMPLETE_TEXT_FIELD_H_ diff --git a/chrome/browser/cocoa/autocomplete_text_field.mm b/chrome/browser/cocoa/autocomplete_text_field.mm index 60d3507..a07cac1 100644 --- a/chrome/browser/cocoa/autocomplete_text_field.mm +++ b/chrome/browser/cocoa/autocomplete_text_field.mm @@ -124,14 +124,10 @@ return; } - // If the user clicked on one of the icons (security icon, Page - // Actions, etc), let the icon handle the click. - for (AutocompleteTextFieldIcon* icon in [cell layedOutIcons:bounds]) { - const NSRect iconRect = [icon rect]; - if (NSMouseInRect(location, iconRect, flipped)) { - [icon view]->OnMousePressed(iconRect); - return; - } + // Give the cell a chance to intercept clicks in page-actions and + // other decorative items. + if ([cell mouseDown:theEvent inRect:bounds ofView:self]) { + return; } NSText* editor = [self currentEditor]; @@ -199,6 +195,7 @@ // Show the I-beam cursor unless the mouse is over an image within the field // (Page Actions or the security icon) in which case show the arrow cursor. +// TODO(rohitrao): Should default to the arrow cursor. http://crbug.com/41612 - (void)resetCursorRects { NSRect fieldBounds = [self bounds]; [self addCursorRect:fieldBounds cursor:[NSCursor IBeamCursor]]; @@ -206,8 +203,17 @@ AutocompleteTextFieldCell* cell = [self autocompleteTextFieldCell]; for (AutocompleteTextFieldIcon* icon in [cell layedOutIcons:fieldBounds]) [self addCursorRect:[icon rect] cursor:[NSCursor arrowCursor]]; + + // Special-case the location image, since it is not in |-layedOutIcons|. + const NSRect locationIconFrame = [cell locationIconFrameForFrame:fieldBounds]; + [self addCursorRect:locationIconFrame cursor:[NSCursor arrowCursor]]; } +// TODO(shess): -resetFieldEditorFrameIfNeeded is the place where +// changes to the cell layout should be flushed. LocationBarViewMac +// and ToolbarController are calling this routine directly, and I +// think they are probably wrong. +// http://crbug.com/40053 - (void)updateCursorAndToolTipRects { // This will force |resetCursorRects| to be called, as it is not to be called // directly. @@ -371,4 +377,13 @@ actionMenuForEvent:event inRect:[self bounds] ofView:self]; } +- (NSRect)starIconFrame { + AutocompleteTextFieldCell* cell = [self autocompleteTextFieldCell]; + return [cell starIconFrameForFrame:[self bounds]]; +} + +- (NSPasteboard*)locationDragPasteboard { + return [[self autocompleteTextFieldCell] locationDragPasteboard]; +} + @end diff --git a/chrome/browser/cocoa/autocomplete_text_field_cell.h b/chrome/browser/cocoa/autocomplete_text_field_cell.h index 1e0a3c5..bc791cf 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_cell.h +++ b/chrome/browser/cocoa/autocomplete_text_field_cell.h @@ -13,7 +13,15 @@ class ExtensionAction; // Holds a |LocationBarImageView| and its current rect. Do not keep references // to this object, only use it directly after calling |-layedOutIcons:|. +// TODO(shess): This class is basically a helper for laying out the +// icons. Try to refactor it away. If that is not reasonable, at +// least split the image and label cases into subclasses once the +// Omnibox stuff is settled. @interface AutocompleteTextFieldIcon : NSObject { + // YES to draw the label part of |view_|, otherwise draw the image + // part. + BOOL isLabel_; + // The frame rect of |view_|. NSRect rect_; @@ -21,12 +29,20 @@ class ExtensionAction; LocationBarViewMac::LocationBarImageView* view_; } -// Returns a new AutocompleteTextFieldIcon object. -+ (AutocompleteTextFieldIcon*) - iconWithRect:(NSRect)rect - view:(LocationBarViewMac::LocationBarImageView*)view; @property(assign, nonatomic) NSRect rect; @property(assign, nonatomic) LocationBarViewMac::LocationBarImageView* view; + +- (id)initImageWithView:(LocationBarViewMac::LocationBarImageView*)view; +- (id)initLabelWithView:(LocationBarViewMac::LocationBarImageView*)view; + +// Position |view_| right-justified in |frame|. +- (void)positionInFrame:(NSRect)frame; + +// Draw image or label of |view_| in |rect_| within |controlView|. +// Only call after |-positionInFrame:| has set |rect_| (or after an +// explicit |-setRect:|). +- (void)drawInView:(NSView*)controlView; + @end // AutocompleteTextFieldCell extends StyledTextFieldCell to provide support for @@ -44,10 +60,17 @@ class ExtensionAction; // side of the field. Exclusive WRT |keywordString_|; scoped_nsobject<NSAttributedString> hintString_; - // View showing the state of the SSL connection. Owned by the location bar. - // Display is exclusive WRT the |hintString_| and |keywordString_|. - // This may be NULL during testing. - LocationBarViewMac::SecurityImageView* security_image_view_; + // The location icon sits at the left-hand side of the field. + // |keywordString_| overrides. + LocationBarViewMac::LocationIconView* locationIconView_; + + // The star icon sits at the right-hand side of the field when an + // URL is being shown. + LocationBarViewMac::LocationBarImageView* starIconView_; + + // The security label floats to the left of page actions at the + // right-hand side. + LocationBarViewMac::LocationBarImageView* securityLabelView_; // List of views showing visible Page Actions. Owned by the location bar. // Display is exclusive WRT the |hintString_| and |keywordString_|. @@ -77,34 +100,58 @@ class ExtensionAction; availableWidth:(CGFloat)width; - (void)clearKeywordAndHint; -- (void)setSecurityImageView:(LocationBarViewMac::SecurityImageView*)view; +- (void)setLocationIconView:(LocationBarViewMac::LocationIconView*)view; +- (void)setStarIconView:(LocationBarViewMac::LocationBarImageView*)view; +- (void)setSecurityLabelView:(LocationBarViewMac::LocationBarImageView*)view; - (void)setPageActionViewList:(LocationBarViewMac::PageActionViewList*)list; - (void)setContentSettingViewsList: (LocationBarViewMac::ContentSettingViews*)views; +// Returns the portion of the cell to use for displaying the location +// icon. +- (NSRect)locationIconFrameForFrame:(NSRect)cellFrame; + // Returns an array of the visible AutocompleteTextFieldIcon objects. Returns // only visible icons. - (NSArray*)layedOutIcons:(NSRect)cellFrame; +// Return the rectangle the star is being shown in, for purposes of +// positioning the bookmark bubble. +- (NSRect)starIconFrameForFrame:(NSRect)cellFrame; + +// Returns the portion of the cell to use for displaying the Page +// Action icon at the given index. May be NSZeroRect if the index's +// action is not visible. This does a linear walk over all page +// actions, so do not call this in a loop to get the position of all +// page actions. Use |-layedOutIcons:| instead in that case. +- (NSRect)pageActionFrameForIndex:(size_t)index inFrame:(NSRect)cellFrame; // Similar to |pageActionFrameForIndex:inFrame| but accepts an // ExtensionAction for when the index is not known. - (NSRect)pageActionFrameForExtensionAction:(ExtensionAction*)action inFrame:(NSRect)cellFrame; -// Returns the portion of the cell to use for displaying the Page Action icon -// at the given index. May be NSZeroRect if the index's action is not visible. -// This does a linear walk over all page actions, so do not call this in a loop -// to get the position of all page actions. Use |-layedOutIcons:| instead in that -// case. -- (NSRect)pageActionFrameForIndex:(size_t)index inFrame:(NSRect)cellFrame; +// Find the icon under the event. |nil| if |theEvent| is not over +// anything. +- (AutocompleteTextFieldIcon*)iconForEvent:(NSEvent*)theEvent + inRect:(NSRect)cellFrame + ofView:(AutocompleteTextField*)controlView; // Return the appropriate menu for any page actions under event. // Returns nil if no menu is present for the action, or if the event // is not over an action. -- (NSMenu*)actionMenuForEvent:(NSEvent*)event +- (NSMenu*)actionMenuForEvent:(NSEvent*)theEvent inRect:(NSRect)cellFrame - ofView:(NSView*)aView; + ofView:(AutocompleteTextField*)controlView; + +// Called by |AutocompleteTextField| to let page actions intercept +// clicks. Returns |YES| if the click has been intercepted. +- (BOOL)mouseDown:(NSEvent*)theEvent + inRect:(NSRect)cellFrame + ofView:(AutocompleteTextField*)controlView; + +// If the location icon is draggable, return its drag pasteboard. +- (NSPasteboard*)locationDragPasteboard; @end @@ -118,8 +165,4 @@ class ExtensionAction; // Returns the total number of installed Page Actions, visible or not. - (size_t)pageActionCount; -// Returns the portion of the cell to use for displaying the security (SSL lock) -// icon, leaving space for its label if any. -- (NSRect)securityImageFrameForFrame:(NSRect)cellFrame; - @end diff --git a/chrome/browser/cocoa/autocomplete_text_field_cell.mm b/chrome/browser/cocoa/autocomplete_text_field_cell.mm index 7b7f35c..9801892 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_cell.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_cell.mm @@ -7,6 +7,20 @@ #include "app/resource_bundle.h" #include "base/logging.h" #include "gfx/font.h" +#include "grit/theme_resources.h" + +@interface AutocompleteTextAttachmentCell : NSTextAttachmentCell { +} + +// TODO(shess): +// Override -cellBaselineOffset to allow the image to be shifted up or +// down relative to the containing text's baseline. + +// Draw the image using |DrawImageInRect()| helper function for +// |-setFlipped:| consistency with other image drawing. +- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView; + +@end namespace { @@ -35,16 +49,28 @@ const NSInteger kKeywordYInset = 4; // technique would be nice to have, though. const NSInteger kKeywordHintImageBaseline = -6; +// Drops the magnifying glass icon so that it looks centered in the +// keyword-search bubble. +const NSInteger kKeywordSearchImageBaseline = -5; + // The amount of padding on either side reserved for drawing an icon. const NSInteger kIconHorizontalPad = 3; // How far to shift bounding box of hint icon label down from top of field. -const NSInteger kIconLabelYOffset = 5; +const NSInteger kIconLabelYOffset = 7; // How far the editor insets itself, for purposes of determining if // decorations need to be trimmed. const CGFloat kEditorHorizontalInset = 3.0; +// Cause the location icon to line up above the icons in the popup. +const CGFloat kLocationIconXOffset = 6.0; +const CGFloat kLocationIconXPad = 1.0; + +// How long to wait for mouse-up on the location icon before assuming +// that the user wants to drag. +const NSTimeInterval kLocationIconDragTimeout = 0.25; + // Conveniences to centralize width+offset calculations. CGFloat WidthForHint(NSAttributedString* hintString) { return kHintXOffset + ceil([hintString size].width); @@ -54,20 +80,103 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { 2 * kKeywordTokenInset; } +// Convenience to draw |image| in the |rect| portion of |view|. +void DrawImageInRect(NSImage* image, NSView* view, const NSRect& rect) { + // If there is an image, make sure we calculated the target size + // correctly. + DCHECK(!image || NSEqualSizes([image size], rect.size)); + [image setFlipped:[view isFlipped]]; + [image drawInRect:rect + fromRect:NSZeroRect // Entire image + operation:NSCompositeSourceOver + fraction:1.0]; +} + +// Helper function to generate an attributed string containing +// |anImage|. If |baselineAdjustment| is 0, the image sits on the +// text baseline, positive values shift it up, negative values shift +// it down. +NSAttributedString* AttributedStringForImage(NSImage* anImage, + CGFloat baselineAdjustment) { + scoped_nsobject<AutocompleteTextAttachmentCell> attachmentCell( + [[AutocompleteTextAttachmentCell alloc] initImageCell:anImage]); + scoped_nsobject<NSTextAttachment> attachment( + [[NSTextAttachment alloc] init]); + [attachment setAttachmentCell:attachmentCell]; + + scoped_nsobject<NSMutableAttributedString> as( + [[NSAttributedString attributedStringWithAttachment:attachment] + mutableCopy]); + [as addAttribute:NSBaselineOffsetAttributeName + value:[NSNumber numberWithFloat:baselineAdjustment] + range:NSMakeRange(0, [as length])]; + + return [[as copy] autorelease]; +} + } // namespace +@implementation AutocompleteTextAttachmentCell + +- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)aView { + // Draw image with |DrawImageInRect()| to get consistent + // |-setFlipped:| treatment. + DrawImageInRect([self image], aView, cellFrame); +} + +@end + @implementation AutocompleteTextFieldIcon @synthesize rect = rect_; @synthesize view = view_; -+ (AutocompleteTextFieldIcon*) - iconWithRect:(NSRect)rect - view:(LocationBarViewMac::LocationBarImageView*)view { - AutocompleteTextFieldIcon* result = [[AutocompleteTextFieldIcon alloc] init]; - [result setRect:rect]; - [result setView:view]; - return [result autorelease]; +// Private helper. +- (id)initWithView:(LocationBarViewMac::LocationBarImageView*)view + isLabel:(BOOL)isLabel { + self = [super init]; + if (self) { + isLabel_ = isLabel; + view_ = view; + rect_ = NSZeroRect; + } + return self; +} + +- (id)initImageWithView:(LocationBarViewMac::LocationBarImageView*)view { + return [self initWithView:view isLabel:NO]; +} + +- (id)initLabelWithView:(LocationBarViewMac::LocationBarImageView*)view { + return [self initWithView:view isLabel:YES]; +} + +- (void)positionInFrame:(NSRect)frame { + if (isLabel_) { + NSAttributedString* label = view_->GetLabel(); + DCHECK(label); + const CGFloat labelWidth = ceil([label size].width); + rect_ = NSMakeRect(NSMaxX(frame) - labelWidth, + NSMinY(frame) + kIconLabelYOffset, + labelWidth, NSHeight(frame) - kIconLabelYOffset); + } else { + const NSSize imageSize = view_->GetImageSize(); + const CGFloat yOffset = floor((NSHeight(frame) - imageSize.height) / 2); + rect_ = NSMakeRect(NSMaxX(frame) - imageSize.width, + NSMinY(frame) + yOffset, + imageSize.width, imageSize.height); + } +} + +- (void)drawInView:(NSView*)controlView { + // Make sure someone called |-positionInFrame:|. + DCHECK(!NSIsEmptyRect(rect_)); + if (isLabel_) { + NSAttributedString* label = view_->GetLabel(); + [label drawInRect:rect_]; + } else { + DrawImageInRect(view_->GetImage(), controlView, rect_); + } } @end @@ -96,18 +205,40 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { // Adjust for space between editor and decorations. width -= 2 * kEditorHorizontalInset; - // If |fullString| won't fit, choose |partialString|. + // Get the magnifying glass to put at the front of the string. + NSImage* image = + AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_SEARCH); + const NSSize imageSize = [image size]; + + // Based on what fits, choose |fullString| with the image, + // |fullString| without the image, or |partialString|. NSDictionary* attributes = [NSDictionary dictionaryWithObject:[self font] forKey:NSFontAttributeName]; NSString* s = fullString; - if ([s sizeWithAttributes:attributes].width > width) { + const CGFloat sWidth = [s sizeWithAttributes:attributes].width; + if (sWidth + imageSize.width > width) { + image = nil; + } + if (sWidth > width) { if (partialString) { s = partialString; } } - keywordString_.reset( - [[NSAttributedString alloc] initWithString:s attributes:attributes]); + + scoped_nsobject<NSMutableAttributedString> as( + [[NSMutableAttributedString alloc] initWithString:s + attributes:attributes]); + + // Insert the image at the front of the string if it didn't make + // things too wide. + if (image) { + NSAttributedString* is = + AttributedStringForImage(image, kKeywordSearchImageBaseline); + [as insertAttributedString:is atIndex:0]; + } + + keywordString_.reset([as copy]); } // Convenience for the attributes used in the right-justified info @@ -155,21 +286,8 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { initWithString:s attributes:[self hintAttributes]]); // Build an attachment containing the hint image. - scoped_nsobject<NSTextAttachmentCell> attachmentCell( - [[NSTextAttachmentCell alloc] initImageCell:anImage]); - scoped_nsobject<NSTextAttachment> attachment( - [[NSTextAttachment alloc] init]); - [attachment setAttachmentCell:attachmentCell]; - - // The attachment's baseline needs to be adjusted so the image - // doesn't sit on the same baseline as the text and make - // everything too tall. - scoped_nsobject<NSMutableAttributedString> is( - [[NSAttributedString attributedStringWithAttachment:attachment] - mutableCopy]); - [is addAttribute:NSBaselineOffsetAttributeName - value:[NSNumber numberWithFloat:kKeywordHintImageBaseline] - range:NSMakeRange(0, [is length])]; + NSAttributedString* is = + AttributedStringForImage(anImage, kKeywordHintImageBaseline); // Stuff the image attachment between the prefix and suffix. [as insertAttributedString:is atIndex:[prefixString length]]; @@ -213,8 +331,16 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { page_action_views_ = list; } -- (void)setSecurityImageView:(LocationBarViewMac::SecurityImageView*)view { - security_image_view_ = view; +- (void)setLocationIconView:(LocationBarViewMac::LocationIconView*)view { + locationIconView_ = view; +} + +- (void)setStarIconView:(LocationBarViewMac::LocationBarImageView*)view { + starIconView_ = view; +} + +- (void)setSecurityLabelView:(LocationBarViewMac::LocationBarImageView*)view { + securityLabelView_ = view; } - (void)setContentSettingViewsList: @@ -226,69 +352,81 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { - (NSRect)textFrameForFrame:(NSRect)cellFrame { NSRect textFrame([super textFrameForFrame:cellFrame]); - if (hintString_) { + // NOTE: This function must closely match the logic in + // |-drawInteriorWithFrame:inView:|. + + // Location icon is not shown in keyword search mode. + if (!keywordString_ && locationIconView_ && locationIconView_->IsVisible()) { + const NSRect iconFrame = [self locationIconFrameForFrame:cellFrame]; + const CGFloat newOrigin = NSMaxX(iconFrame) + kLocationIconXPad; + textFrame.size.width = NSMaxX(textFrame) - newOrigin; + textFrame.origin.x = newOrigin; + } + + // Leave room for items on the right (SSL label, page actions, etc). + // Icons are laid out in |cellFrame| rather than |textFrame| for + // consistency with drawing code. + NSArray* icons = [self layedOutIcons:cellFrame]; + if ([icons count]) { + // Max x for resulting text frame. + const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]); + textFrame.size.width = maxX - NSMinX(textFrame); + } + + // Keyword string or hint string if they fit. + if (keywordString_) { + DCHECK(!hintString_); + const CGFloat keywordWidth(WidthForKeyword(keywordString_)); + + if (keywordWidth < NSWidth(textFrame)) { + textFrame.origin.x += keywordWidth; + textFrame.size.width -= keywordWidth; + } + } else if (hintString_) { DCHECK(!keywordString_); const CGFloat hintWidth(WidthForHint(hintString_)); // TODO(shess): This could be better. Show the hint until the // non-hint text bumps against it? - if (hintWidth < NSWidth(cellFrame)) { + if (hintWidth < NSWidth(textFrame)) { textFrame.size.width -= hintWidth; } - } else if (keywordString_) { - DCHECK(!hintString_); - const CGFloat keywordWidth(WidthForKeyword(keywordString_)); + } - // TODO(shess): This could be better. There's support for a - // "short" version of the keyword string, work that in in a - // follow-on pass. - if (keywordWidth < NSWidth(cellFrame)) { - textFrame.origin.x += keywordWidth; - textFrame.size.width = NSMaxX(cellFrame) - NSMinX(textFrame); + // SSL label if it fits. + if (securityLabelView_ && securityLabelView_->IsVisible() && + securityLabelView_->GetLabel()) { + NSAttributedString* label = securityLabelView_->GetLabel(); + const CGFloat labelWidth = ceil([label size].width) + kIconHorizontalPad; + if (NSWidth(textFrame) > labelWidth) { + textFrame.size.width -= labelWidth; } - } else { - // Leave room for images on the right (lock icon etc). - NSArray* iconFrames = [self layedOutIcons:cellFrame]; - CGFloat width = 0; - if ([iconFrames count] > 0) - width = NSMaxX(cellFrame) - NSMinX([[iconFrames lastObject] rect]); - if (width > 0) - width += kIconHorizontalPad; - if (width < NSWidth(cellFrame)) - textFrame.size.width -= width; } return textFrame; } -// Returns a rect of size |imageSize| centered vertically and right-justified in -// the |box|, with its top left corner |margin| pixels from the right end of the -// box. (The image thus occupies part of the |margin|.) -- (NSRect)rightJustifyImage:(NSSize)imageSize - inRect:(NSRect)box - withMargin:(CGFloat)margin { - box.origin.x += box.size.width - margin; - box.origin.y += floor((box.size.height - imageSize.height) / 2); - box.size = imageSize; - return box; +- (NSRect)locationIconFrameForFrame:(NSRect)cellFrame { + if (!locationIconView_ || !locationIconView_->IsVisible()) + return NSZeroRect; + + const NSSize imageSize = locationIconView_->GetImageSize(); + const CGFloat yOffset = floor((NSHeight(cellFrame) - imageSize.height) / 2); + return NSMakeRect(NSMinX(cellFrame) + kLocationIconXOffset, + NSMinY(cellFrame) + yOffset, + imageSize.width, imageSize.height); } -- (NSRect)securityImageFrameForFrame:(NSRect)cellFrame { - if (!security_image_view_ || !security_image_view_->IsVisible()) { +- (NSRect)starIconFrameForFrame:(NSRect)cellFrame { + if (!starIconView_ || !starIconView_->IsVisible()) return NSZeroRect; - } - - // Calculate the total width occupied by the image, label, and padding. - NSSize imageSize = [security_image_view_->GetImage() size]; - CGFloat widthUsed = imageSize.width + kIconHorizontalPad; - NSAttributedString* label = security_image_view_->GetLabel(); - if (label) { - widthUsed += ceil([label size].width) + kHintXOffset; - } - return [self rightJustifyImage:imageSize - inRect:cellFrame - withMargin:widthUsed]; + // The star icon is always at the RHS. + scoped_nsobject<AutocompleteTextFieldIcon> icon( + [[AutocompleteTextFieldIcon alloc] initImageWithView:starIconView_]); + cellFrame.size.width -= kHintXOffset; + [icon positionInFrame:cellFrame]; + return [icon rect]; } - (size_t)pageActionCount { @@ -365,118 +503,223 @@ CGFloat WidthForKeyword(NSAttributedString* keywordString) { [path stroke]; // Draw text w/in the rectangle. - infoFrame.origin.x += 4.0; - infoFrame.origin.y += 1.0; + infoFrame.origin.x += 3.0; [keywordString_.get() drawInRect:infoFrame]; } -- (void)drawImageView:(LocationBarViewMac::LocationBarImageView*)imageView - inFrame:(NSRect)imageFrame - inView:(NSView*)controlView { - // If there's a label, draw it to the right of the icon. The caller must have - // left sufficient space. - NSAttributedString* label = imageView->GetLabel(); - if (label) { - CGFloat labelWidth = ceil([label size].width) + kHintXOffset; - NSRect textFrame(NSMakeRect(NSMaxX(imageFrame) + kIconHorizontalPad, - imageFrame.origin.y + kIconLabelYOffset, - labelWidth, - imageFrame.size.height - kIconLabelYOffset)); - [label drawInRect:textFrame]; +- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { + NSRect workingFrame = cellFrame; + + // NOTE: This function must closely match the logic in + // |-textFrameForFrame:|. + + // Location icon is not shown in keyword search mode. + if (!keywordString_ && locationIconView_ && locationIconView_->IsVisible()) { + const NSRect iconFrame = [self locationIconFrameForFrame:cellFrame]; + DrawImageInRect(locationIconView_->GetImage(), controlView, iconFrame); + const CGFloat newOrigin = NSMaxX(iconFrame) + kLocationIconXPad; + workingFrame.size.width = NSMaxX(workingFrame) - newOrigin; + workingFrame.origin.x = newOrigin; } - // Draw the entire image. - NSRect imageRect = NSZeroRect; - NSImage* image = imageView->GetImage(); - image.size = [image size]; - [image setFlipped:[controlView isFlipped]]; - [image drawInRect:imageFrame - fromRect:imageRect - operation:NSCompositeSourceOver - fraction:1.0]; -} + NSArray* icons = [self layedOutIcons:cellFrame]; + for (AutocompleteTextFieldIcon* icon in icons) { + [icon drawInView:controlView]; + } + if ([icons count]) { + // Max x for resulting text frame. + const CGFloat maxX = NSMinX([[icons objectAtIndex:0] rect]); + workingFrame.size.width = maxX - NSMinX(workingFrame); + } -- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - if (hintString_) { - [self drawHintWithFrame:cellFrame inView:controlView]; - } else if (keywordString_) { - [self drawKeywordWithFrame:cellFrame inView:controlView]; - } else { - for (AutocompleteTextFieldIcon* icon in [self layedOutIcons:cellFrame]) { - [self drawImageView:[icon view] - inFrame:[icon rect] - inView:controlView]; + // Keyword string or hint string if they fit. + if (keywordString_) { + DCHECK(!hintString_); + const CGFloat keywordWidth(WidthForKeyword(keywordString_)); + + if (keywordWidth < NSWidth(workingFrame)) { + [self drawKeywordWithFrame:cellFrame inView:controlView]; + workingFrame.origin.x += keywordWidth; + workingFrame.size.width -= keywordWidth; + } + } else if (hintString_) { + DCHECK(!keywordString_); + const CGFloat hintWidth(WidthForHint(hintString_)); + + // TODO(shess): This could be better. Show the hint until the + // non-hint text bumps against it? + if (hintWidth < NSWidth(workingFrame)) { + [self drawHintWithFrame:cellFrame inView:controlView]; + workingFrame.size.width -= hintWidth; } } + // SSL label if it fits. + if (securityLabelView_ && securityLabelView_->IsVisible() && + securityLabelView_->GetLabel()) { + NSAttributedString* label = securityLabelView_->GetLabel(); + const CGFloat labelWidth = ceil([label size].width) + kIconHorizontalPad; + if (NSWidth(workingFrame) > labelWidth) { + workingFrame.size.width -= kIconHorizontalPad; + + scoped_nsobject<AutocompleteTextFieldIcon> icon( + [[AutocompleteTextFieldIcon alloc] + initLabelWithView:securityLabelView_]); + [icon positionInFrame:workingFrame]; + [icon drawInView:controlView]; + DCHECK_EQ(labelWidth, NSWidth([icon rect]) + kIconHorizontalPad); + workingFrame.size.width -= NSWidth([icon rect]); + } + } + + // Superclass draws text portion WRT original |cellFrame|. [super drawInteriorWithFrame:cellFrame inView:controlView]; } - (NSArray*)layedOutIcons:(NSRect)cellFrame { - NSMutableArray* result = [NSMutableArray arrayWithCapacity:0]; - NSRect iconFrame = cellFrame; - if (security_image_view_ && security_image_view_->IsVisible()) { - NSRect securityImageFrame = [self securityImageFrameForFrame:iconFrame]; - [result addObject: - [AutocompleteTextFieldIcon iconWithRect:securityImageFrame - view:security_image_view_]]; - iconFrame.size.width -= NSMaxX(iconFrame) - NSMinX(securityImageFrame); + // The set of views to display right-justified in the cell, from + // left to right. + NSMutableArray* result = [NSMutableArray array]; + + // Collect the image views for bulk processing. + // TODO(shess): Refactor with LocationBarViewMac to make the + // different types of items more consistent. + std::vector<LocationBarViewMac::LocationBarImageView*> views; + + if (content_setting_views_) { + views.insert(views.end(), + content_setting_views_->begin(), + content_setting_views_->end()); } - const size_t pageActionCount = [self pageActionCount]; - for (size_t i = 0; i < pageActionCount; ++i) { - LocationBarViewMac::PageActionImageView* view = - page_action_views_->ViewAt(i); - if (view->IsVisible()) { - // If this function is called right after a page action icon has been - // created, the images for all views will still be loading; in this case, - // each visible view will give us its default size. - NSSize iconSize = view->GetPreferredImageSize(); - NSRect pageActionFrame = - [self rightJustifyImage:iconSize - inRect:iconFrame - withMargin:kIconHorizontalPad + iconSize.width]; - [result addObject: - [AutocompleteTextFieldIcon iconWithRect:pageActionFrame view:view]]; - iconFrame.size.width -= NSMaxX(iconFrame) - NSMinX(pageActionFrame); - } + // TODO(shess): Previous implementation of this method made a + // right-to-left array, so add the page-action items in that order. + // As part of the refactor mentioned above, lay everything out + // nicely left-to-right. + for (size_t i = [self pageActionCount]; i-- > 0;) { + views.push_back(page_action_views_->ViewAt(i)); } - if (content_setting_views_) { - // We use a reverse_iterator here because we're laying out the views from - // right to left but in the vector they're ordered left to right. - for (LocationBarViewMac::ContentSettingViews::const_reverse_iterator - it(content_setting_views_->rbegin()); - it != const_cast<const LocationBarViewMac::ContentSettingViews*>( - content_setting_views_)->rend(); - ++it) { - if ((*it)->IsVisible()) { - NSImage* image = (*it)->GetImage(); - NSRect blockedContentFrame = - [self rightJustifyImage:[image size] - inRect:iconFrame - withMargin:[image size].width + kIconHorizontalPad]; - [result addObject: - [AutocompleteTextFieldIcon iconWithRect:blockedContentFrame - view:*it]]; - iconFrame.size.width -= NSMaxX(iconFrame) - NSMinX(blockedContentFrame); - } + // The star icon should always come last. + if (starIconView_) + views.push_back(starIconView_); + + // Load the visible views into |result|. + for (std::vector<LocationBarViewMac::LocationBarImageView*>::const_iterator + iter = views.begin(); iter != views.end(); ++iter) { + if ((*iter)->IsVisible()) { + scoped_nsobject<AutocompleteTextFieldIcon> icon( + [[AutocompleteTextFieldIcon alloc] initImageWithView:*iter]); + [result addObject:icon]; } } + + // Leave a boundary at RHS of field. + cellFrame.size.width -= kHintXOffset; + + // Position each view within the frame from right to left. + for (AutocompleteTextFieldIcon* icon in [result reverseObjectEnumerator]) { + [icon positionInFrame:cellFrame]; + + // Trim the icon's space from the frame. + cellFrame.size.width = NSMinX([icon rect]) - kIconHorizontalPad; + } return result; } -- (NSMenu*)actionMenuForEvent:(NSEvent*)event - inRect:(NSRect)cellFrame - ofView:(NSView*)aView { - NSPoint location = [aView convertPoint:[event locationInWindow] fromView:nil]; +- (AutocompleteTextFieldIcon*)iconForEvent:(NSEvent*)theEvent + inRect:(NSRect)cellFrame + ofView:(AutocompleteTextField*)controlView { + const BOOL flipped = [controlView isFlipped]; + const NSPoint location = + [controlView convertPoint:[theEvent locationInWindow] fromView:nil]; + + // Special check for location image, it is not in |-layedOutIcons:|. + const NSRect locationIconFrame = [self locationIconFrameForFrame:cellFrame]; + if (NSMouseInRect(location, locationIconFrame, flipped)) { + // Make up an icon to return. + AutocompleteTextFieldIcon* icon = + [[[AutocompleteTextFieldIcon alloc] + initImageWithView:locationIconView_] autorelease]; + [icon setRect:locationIconFrame]; + return icon; + } - const BOOL flipped = [aView isFlipped]; for (AutocompleteTextFieldIcon* icon in [self layedOutIcons:cellFrame]) { - if (NSMouseInRect(location, [icon rect], flipped)) { - return [icon view]->GetMenu(); + if (NSMouseInRect(location, [icon rect], flipped)) + return icon; + } + + return nil; +} + +- (NSMenu*)actionMenuForEvent:(NSEvent*)theEvent + inRect:(NSRect)cellFrame + ofView:(AutocompleteTextField*)controlView { + AutocompleteTextFieldIcon* + icon = [self iconForEvent:theEvent inRect:cellFrame ofView:controlView]; + if (icon) + return [icon view]->GetMenu(); + return nil; +} + +- (BOOL)mouseDown:(NSEvent*)theEvent + inRect:(NSRect)cellFrame + ofView:(AutocompleteTextField*)controlView { + AutocompleteTextFieldIcon* icon = + [self iconForEvent:theEvent inRect:cellFrame ofView:controlView]; + if (!icon) + return NO; + + // If the icon is draggable, then initiate a drag if the user drags + // or holds the mouse down for awhile. + if ([icon view]->IsDraggable()) { + NSDate* timeout = + [NSDate dateWithTimeIntervalSinceNow:kLocationIconDragTimeout]; + NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask | + NSLeftMouseUpMask) + untilDate:timeout + inMode:NSEventTrackingRunLoopMode + dequeue:YES]; + if (!event || [event type] == NSLeftMouseDragged) { + NSPasteboard* pboard = [icon view]->GetDragPasteboard(); + DCHECK(pboard); + + // TODO(shess): My understanding is that the -isFlipped + // adjustment should not be necessary. But without it, the + // image is nowhere near the cursor. Perhaps the icon's rect is + // incorrectly calculated? + // http://crbug.com/40711 + NSPoint dragPoint = [icon rect].origin; + if ([controlView isFlipped]) + dragPoint.y += NSHeight([icon rect]); + + [controlView dragImage:[icon view]->GetImage() + at:dragPoint + offset:NSZeroSize + event:event ? event : theEvent + pasteboard:pboard + source:self + slideBack:YES]; + return YES; } + + // On mouse-up fall through to mouse-pressed case. + DCHECK_EQ([event type], NSLeftMouseUp); } + + [icon view]->OnMousePressed([icon rect]); + return YES; +} + +- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { + return NSDragOperationCopy; +} + +- (NSPasteboard*)locationDragPasteboard { + if (locationIconView_ && locationIconView_->IsDraggable()) + return locationIconView_->GetDragPasteboard(); + return nil; } diff --git a/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm b/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm index 0a16c48..5bd02cc 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_cell_unittest.mm @@ -4,9 +4,11 @@ #import <Cocoa/Cocoa.h> +#include "app/resource_bundle.h" #include "base/scoped_nsobject.h" #import "chrome/browser/cocoa/autocomplete_text_field_cell.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" +#include "grit/theme_resources.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -43,7 +45,7 @@ class TestPageActionViewList : public LocationBarViewMac::PageActionViewList { class AutocompleteTextFieldCellTest : public CocoaTest { public: - AutocompleteTextFieldCellTest() : security_image_view_(NULL, NULL, NULL), + AutocompleteTextFieldCellTest() : location_icon_view_(NULL), page_action_views_() { // Make sure this is wide enough to play games with the cell // decorations. @@ -57,7 +59,8 @@ class AutocompleteTextFieldCellTest : public CocoaTest { [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]); [cell setEditable:YES]; [cell setBordered:YES]; - [cell setSecurityImageView:&security_image_view_]; + [cell setLocationIconView:&location_icon_view_]; + [cell setSecurityLabelView:&security_label_view_]; [cell setPageActionViewList:&page_action_views_]; [view_ setCell:cell.get()]; @@ -65,7 +68,8 @@ class AutocompleteTextFieldCellTest : public CocoaTest { } NSTextField* view_; - LocationBarViewMac::SecurityImageView security_image_view_; + LocationBarViewMac::LocationIconView location_icon_view_; + LocationBarViewMac::LocationBarImageView security_label_view_; TestPageActionViewList page_action_views_; }; @@ -199,15 +203,16 @@ TEST_F(AutocompleteTextFieldCellTest, TextFrame) { EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame)); EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame)); - // Security icon takes up space on the right - security_image_view_.SetImageShown( - LocationBarViewMac::SecurityImageView::LOCK); - security_image_view_.SetVisible(true); + // Location icon takes up space on the left + location_icon_view_.SetImage( + ResourceBundle::GetSharedInstance().GetNSImageNamed( + IDR_OMNIBOX_HTTPS_VALID)); + location_icon_view_.SetVisible(true); textFrame = [cell textFrameForFrame:bounds]; EXPECT_FALSE(NSIsEmptyRect(textFrame)); EXPECT_TRUE(NSContainsRect(bounds, textFrame)); - EXPECT_LT(NSMaxX(textFrame), NSMaxX(bounds)); + EXPECT_GT(NSMinX(textFrame), NSMinX(bounds)); EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame)); // Search hint text takes precedence over the hint icon; the text frame @@ -265,9 +270,10 @@ TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) { EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect)); EXPECT_TRUE(NSEqualRects(drawingRect, originalDrawingRect)); - security_image_view_.SetImageShown( - LocationBarViewMac::SecurityImageView::LOCK); - security_image_view_.SetVisible(true); + location_icon_view_.SetImage( + ResourceBundle::GetSharedInstance().GetNSImageNamed( + IDR_OMNIBOX_HTTPS_VALID)); + location_icon_view_.SetVisible(true); textFrame = [cell textFrameForFrame:bounds]; drawingRect = [cell drawingRectForBounds:bounds]; @@ -275,55 +281,60 @@ TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) { EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect)); } -// Test that the security icon is at the right side of the cell. -TEST_F(AutocompleteTextFieldCellTest, SecurityImageFrame) { +// Test that the location icon is at the right side of the cell. +TEST_F(AutocompleteTextFieldCellTest, LocationIconFrame) { AutocompleteTextFieldCell* cell = static_cast<AutocompleteTextFieldCell*>([view_ cell]); const NSRect bounds([view_ bounds]); - security_image_view_.SetImageShown( - LocationBarViewMac::SecurityImageView::LOCK); - - security_image_view_.SetVisible(false); - EXPECT_EQ(0u, [[cell layedOutIcons:bounds] count]); - - security_image_view_.SetVisible(true); - NSArray* icons = [cell layedOutIcons:bounds]; - ASSERT_EQ(1u, [icons count]); - NSRect iconRect = [[icons objectAtIndex:0] rect]; + location_icon_view_.SetImage( + ResourceBundle::GetSharedInstance().GetNSImageNamed( + IDR_OMNIBOX_HTTPS_VALID)); + location_icon_view_.SetVisible(true); + const NSRect iconRect = [cell locationIconFrameForFrame:bounds]; EXPECT_FALSE(NSIsEmptyRect(iconRect)); EXPECT_TRUE(NSContainsRect(bounds, iconRect)); - // Make sure we are right of the |drawingRect|. - NSRect drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_LE(NSMaxX(drawingRect), NSMinX(iconRect)); + // Location icon should be left of |drawingRect|. + const NSRect drawingRect = [cell drawingRectForBounds:bounds]; + EXPECT_GT(NSMinX(drawingRect), NSMinX(iconRect)); - // Make sure we're right of the |textFrame|. - NSRect textFrame = [cell textFrameForFrame:bounds]; - EXPECT_LE(NSMaxX(textFrame), NSMinX(iconRect)); + // Location icon should be left of |textFrame|. + const NSRect textFrame = [cell textFrameForFrame:bounds]; + EXPECT_GT(NSMinX(textFrame), NSMinX(iconRect)); +} + +// Test that security label takes space to the right. +TEST_F(AutocompleteTextFieldCellTest, SecurityLabelFrame) { + AutocompleteTextFieldCell* cell = + static_cast<AutocompleteTextFieldCell*>([view_ cell]); + const NSRect bounds([view_ bounds]); + + // No label shows nothing, regardless of visibility setting. + security_label_view_.SetVisible(false); + const NSRect baseTextFrame = [cell textFrameForFrame:bounds]; + security_label_view_.SetVisible(true); + EXPECT_TRUE(NSEqualRects(baseTextFrame, [cell textFrameForFrame:bounds])); - // Now add a label. + // Still not visible even with a label. NSFont* font = [NSFont controlContentFontOfSize:12.0]; NSColor* color = [NSColor blackColor]; - security_image_view_.SetLabel(@"Label", font, color); - icons = [cell layedOutIcons:bounds]; - ASSERT_EQ(1u, [icons count]); - iconRect = [[icons objectAtIndex:0] rect]; + security_label_view_.SetLabel(@"Label", font, color); + security_label_view_.SetVisible(false); + EXPECT_TRUE(NSEqualRects(baseTextFrame, [cell textFrameForFrame:bounds])); - EXPECT_FALSE(NSIsEmptyRect(iconRect)); - EXPECT_TRUE(NSContainsRect(bounds, iconRect)); - - // Make sure we are right of the |drawingRect|. - drawingRect = [cell drawingRectForBounds:bounds]; - EXPECT_LE(NSMaxX(drawingRect), NSMinX(iconRect)); + // Visible with a label is strictly narrower than without. + security_label_view_.SetVisible(true); + NSRect textFrame = [cell textFrameForFrame:bounds]; + const CGFloat labelWidth = [security_label_view_.GetLabel() size].width; + EXPECT_TRUE(NSContainsRect(baseTextFrame, textFrame)); + EXPECT_LT(NSWidth(textFrame), NSWidth(baseTextFrame) - labelWidth); - // Make sure we're right of the |textFrame|. + NSString* longLabel = + @"Really super-long labels will not show up if there's not enough room."; + security_label_view_.SetLabel(longLabel, font, color); textFrame = [cell textFrameForFrame:bounds]; - EXPECT_LE(NSMaxX(textFrame), NSMinX(iconRect)); - - // Make sure we clear correctly. - security_image_view_.SetVisible(false); - EXPECT_EQ(0u, [[cell layedOutIcons:bounds] count]); + EXPECT_TRUE(NSEqualRects(baseTextFrame, [cell textFrameForFrame:bounds])); } // Test Page Action counts. @@ -349,8 +360,6 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) { AutocompleteTextFieldCell* cell = static_cast<AutocompleteTextFieldCell*>([view_ cell]); const NSRect bounds([view_ bounds]); - security_image_view_.SetImageShown( - LocationBarViewMac::SecurityImageView::LOCK); TestPageActionImageView page_action_view; // We'll assume that the extensions code enforces icons smaller than the @@ -368,13 +377,12 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) { list.Add(&page_action_view2); [cell setPageActionViewList:&list]; - security_image_view_.SetVisible(false); page_action_view.SetVisible(false); page_action_view2.SetVisible(false); EXPECT_TRUE(NSIsEmptyRect([cell pageActionFrameForIndex:0 inFrame:bounds])); EXPECT_TRUE(NSIsEmptyRect([cell pageActionFrameForIndex:1 inFrame:bounds])); - // One page action, no security icon. + // One page action, no lock icon. page_action_view.SetVisible(true); NSRect iconRect0 = [cell pageActionFrameForIndex:0 inFrame:bounds]; @@ -389,17 +397,19 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) { NSRect textFrame = [cell textFrameForFrame:bounds]; EXPECT_LE(NSMaxX(textFrame), NSMinX(iconRect0)); - // Two page actions plus a security icon. + // Two page actions plus a security label. page_action_view2.SetVisible(true); - security_image_view_.SetVisible(true); NSArray* icons = [cell layedOutIcons:bounds]; - EXPECT_EQ(3u, [icons count]); + ASSERT_EQ(2u, [icons count]); + + // TODO(shess): page-action list is inverted from -layedOutIcons: + // Yes, this is confusing, fix it. iconRect0 = [cell pageActionFrameForIndex:0 inFrame:bounds]; NSRect iconRect1 = [cell pageActionFrameForIndex:1 inFrame:bounds]; - NSRect lockRect = [[icons objectAtIndex:0] rect]; + NSRect labelRect = [[icons objectAtIndex:0] rect]; EXPECT_TRUE(NSEqualRects(iconRect0, [[icons objectAtIndex:1] rect])); - EXPECT_TRUE(NSEqualRects(iconRect1, [[icons objectAtIndex:2] rect])); + EXPECT_TRUE(NSEqualRects(iconRect1, [[icons objectAtIndex:0] rect])); // Make sure they're all in the expected order, and right of the |drawingRect| // and |textFrame|. @@ -410,13 +420,13 @@ TEST_F(AutocompleteTextFieldCellTest, PageActionImageFrame) { EXPECT_TRUE(NSContainsRect(bounds, iconRect0)); EXPECT_FALSE(NSIsEmptyRect(iconRect1)); EXPECT_TRUE(NSContainsRect(bounds, iconRect1)); - EXPECT_FALSE(NSIsEmptyRect(lockRect)); - EXPECT_TRUE(NSContainsRect(bounds, lockRect)); + EXPECT_FALSE(NSIsEmptyRect(labelRect)); + EXPECT_TRUE(NSContainsRect(bounds, labelRect)); EXPECT_LE(NSMaxX(drawingRect), NSMinX(iconRect1)); EXPECT_LE(NSMaxX(textFrame), NSMinX(iconRect1)); EXPECT_LE(NSMaxX(iconRect1), NSMinX(iconRect0)); - EXPECT_LE(NSMaxX(iconRect0), NSMinX(lockRect)); + EXPECT_LE(NSMaxX(labelRect), NSMinX(iconRect0)); } // Test that the cell correctly chooses the partial keyword if there's @@ -428,11 +438,22 @@ TEST_F(AutocompleteTextFieldCellTest, UsesPartialKeywordIfNarrow) { const NSString* kFullString = @"Search Engine:"; const NSString* kPartialString = @"Search Eng:"; - // Wide width chooses the full string. + // Wide width chooses the full string, including an image on the + // left. [cell setKeywordString:kFullString partialString:kPartialString availableWidth:kWidth]; EXPECT_TRUE([cell keywordString]); + EXPECT_TRUE([[[cell keywordString] string] hasSuffix:kFullString]); + EXPECT_TRUE([[cell keywordString] containsAttachments]); + + // If not enough space to include the image, uses exactly the full + // string. + CGFloat allWidth = [[cell keywordString] size].width; + [cell setKeywordString:kFullString + partialString:kPartialString + availableWidth:allWidth - 5.0]; + EXPECT_TRUE([cell keywordString]); EXPECT_TRUE([[[cell keywordString] string] isEqualToString:kFullString]); // Narrow width chooses the partial string. diff --git a/chrome/browser/cocoa/autocomplete_text_field_editor.mm b/chrome/browser/cocoa/autocomplete_text_field_editor.mm index 70aa5cd..974b346 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_editor.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_editor.mm @@ -33,6 +33,35 @@ class Extension; return self; } +// If the entire field is selected, drag the same data as would be +// dragged from the field's location icon. In some cases the textual +// contents will not contain relevant data (for instance, "http://" is +// stripped from URLs). +- (BOOL)dragSelectionWithEvent:(NSEvent *)event + offset:(NSSize)mouseOffset + slideBack:(BOOL)slideBack { + const NSRange allRange = NSMakeRange(0, [[self textStorage] length]); + if (NSEqualRanges(allRange, [self selectedRange])) { + NSPasteboard* pboard = [[self delegate] locationDragPasteboard]; + if (pboard) { + NSPoint p; + NSImage* image = [self dragImageForSelectionWithEvent:event origin:&p]; + + [self dragImage:image + at:p + offset:mouseOffset + event:event + pasteboard:pboard + source:self + slideBack:slideBack]; + return YES; + } + } + return [super dragSelectionWithEvent:event + offset:mouseOffset + slideBack:slideBack]; +} + - (void)copy:(id)sender { AutocompleteTextFieldObserver* observer = [self observer]; DCHECK(observer); diff --git a/chrome/browser/cocoa/autocomplete_text_field_unittest.mm b/chrome/browser/cocoa/autocomplete_text_field_unittest.mm index d695f86..1d0ae49 100644 --- a/chrome/browser/cocoa/autocomplete_text_field_unittest.mm +++ b/chrome/browser/cocoa/autocomplete_text_field_unittest.mm @@ -4,6 +4,7 @@ #import <Cocoa/Cocoa.h> +#include "app/resource_bundle.h" #import "base/cocoa_protocols_mac.h" #include "base/scoped_nsobject.h" #import "chrome/browser/cocoa/autocomplete_text_field.h" @@ -11,6 +12,7 @@ #import "chrome/browser/cocoa/autocomplete_text_field_editor.h" #import "chrome/browser/cocoa/autocomplete_text_field_unittest_helper.h" #import "chrome/browser/cocoa/cocoa_test_helper.h" +#include "grit/theme_resources.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -20,18 +22,34 @@ using ::testing::Return; using ::testing::StrictMock; namespace { -class MockSecurityImageView : public LocationBarViewMac::SecurityImageView { +class MockLocationIconView : public LocationBarViewMac::LocationIconView { public: - MockSecurityImageView(LocationBarViewMac* owner, - Profile* profile, - ToolbarModel* model) - : LocationBarViewMac::SecurityImageView(owner, profile, model) {} + MockLocationIconView() + : LocationBarViewMac::LocationIconView(NULL), + is_draggable_(false), + mouse_was_pressed_(false) {} + + // |LocationBarViewMac::LocationIconView| dragging support needs + // more setup than this test provides. + bool IsDraggable() { + return is_draggable_; + } + virtual NSPasteboard* GetDragPasteboard() { + return [NSPasteboard pasteboardWithUniqueName]; + } + void SetDraggable(bool is_draggable) { + is_draggable_ = is_draggable; + } // We can't use gmock's MOCK_METHOD macro, because it doesn't like the // NSRect argument to OnMousePressed. virtual void OnMousePressed(NSRect bounds) { mouse_was_pressed_ = true; } + bool MouseWasPressed() { return mouse_was_pressed_; } + + private: + bool is_draggable_; bool mouse_was_pressed_; }; @@ -582,32 +600,35 @@ TEST_F(AutocompleteTextFieldTest, TripleClickSelectsAll) { } // Clicking the security icon should call its OnMousePressed. -TEST_F(AutocompleteTextFieldObserverTest, SecurityIconMouseDown) { +TEST_F(AutocompleteTextFieldTest, LocationIconMouseDown) { AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; - MockSecurityImageView security_image_view(NULL, NULL, NULL); - [cell setSecurityImageView:&security_image_view]; - security_image_view.SetImageShown( - LocationBarViewMac::SecurityImageView::LOCK); - security_image_view.SetVisible(true); + MockLocationIconView location_icon_view; + [cell setLocationIconView:&location_icon_view]; + location_icon_view.SetImage( + ResourceBundle::GetSharedInstance().GetNSImageNamed( + IDR_OMNIBOX_HTTPS_VALID)); + location_icon_view.SetVisible(true); - NSRect iconFrame([cell securityImageFrameForFrame:[field_ bounds]]); + NSRect iconFrame([cell locationIconFrameForFrame:[field_ bounds]]); NSPoint location(NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame))); - NSEvent* event(Event(field_, location, NSLeftMouseDown, 1)); + NSEvent* downEvent(Event(field_, location, NSLeftMouseDown, 1)); + NSEvent* upEvent(Event(field_, location, NSLeftMouseUp, 1)); - [field_ mouseDown:event]; - EXPECT_TRUE(security_image_view.mouse_was_pressed_); + // Since location icon can be dragged, the mouse-press is sent on + // mouse-up. + [NSApp postEvent:upEvent atStart:YES]; + [field_ mouseDown:downEvent]; + EXPECT_TRUE(location_icon_view.MouseWasPressed()); + + // TODO(shess): Test that mouse drags are initiated if the next + // event is a drag, or if the mouse-up takes too long to arrive. } // Clicking a Page Action icon should call its OnMousePressed. -TEST_F(AutocompleteTextFieldObserverTest, PageActionMouseDown) { +TEST_F(AutocompleteTextFieldTest, PageActionMouseDown) { AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; - MockSecurityImageView security_image_view(NULL, NULL, NULL); - security_image_view.SetImageShown( - LocationBarViewMac::SecurityImageView::LOCK); - [cell setSecurityImageView:&security_image_view]; - MockPageActionImageView page_action_view; NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"]; page_action_view.SetImage(image); @@ -620,8 +641,7 @@ TEST_F(AutocompleteTextFieldObserverTest, PageActionMouseDown) { list.Add(&page_action_view2); [cell setPageActionViewList:&list]; - // One page action, no security lock. - security_image_view.SetVisible(false); + // One page action. page_action_view.SetVisible(true); page_action_view2.SetVisible(false); NSRect iconFrame([cell pageActionFrameForIndex:0 inFrame:[field_ bounds]]); @@ -631,7 +651,7 @@ TEST_F(AutocompleteTextFieldObserverTest, PageActionMouseDown) { [field_ mouseDown:event]; EXPECT_TRUE(page_action_view.MouseWasPressed()); - // Two page actions, no security lock. + // Two page actions, no lock. page_action_view2.SetVisible(true); iconFrame = [cell pageActionFrameForIndex:0 inFrame:[field_ bounds]]; location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); @@ -647,8 +667,7 @@ TEST_F(AutocompleteTextFieldObserverTest, PageActionMouseDown) { [field_ mouseDown:event]; EXPECT_TRUE(page_action_view.MouseWasPressed()); - // Two page actions plus security lock. - security_image_view.SetVisible(true); + // Two page actions. iconFrame = [cell pageActionFrameForIndex:0 inFrame:[field_ bounds]]; location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); event = Event(field_, location, NSLeftMouseDown, 1); @@ -662,13 +681,6 @@ TEST_F(AutocompleteTextFieldObserverTest, PageActionMouseDown) { [field_ mouseDown:event]; EXPECT_TRUE(page_action_view.MouseWasPressed()); - - iconFrame = [cell securityImageFrameForFrame:[field_ bounds]]; - location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame)); - event = Event(field_, location, NSLeftMouseDown, 1); - - [field_ mouseDown:event]; - EXPECT_TRUE(security_image_view.mouse_was_pressed_); } // Test that page action menus are properly returned. @@ -860,4 +872,22 @@ TEST_F(AutocompleteTextFieldObserverTest, SendsOnResignKey) { [test_window() resignKeyWindow]; } +TEST_F(AutocompleteTextFieldTest, LocationDragPasteboard) { + AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; + + MockLocationIconView location_icon_view; + location_icon_view.SetImage( + ResourceBundle::GetSharedInstance().GetNSImageNamed( + IDR_OMNIBOX_HTTPS_VALID)); + location_icon_view.SetVisible(true); + [cell setLocationIconView:&location_icon_view]; + + // Not draggable, so no pasteboard. + EXPECT_FALSE([field_ locationDragPasteboard]); + + // Gets a pasteboard when draggable. + location_icon_view.SetDraggable(true); + EXPECT_TRUE([field_ locationDragPasteboard]); +} + } // namespace diff --git a/chrome/browser/cocoa/bookmark_bubble_controller.mm b/chrome/browser/cocoa/bookmark_bubble_controller.mm index fc2ff7b..465691e 100644 --- a/chrome/browser/cocoa/bookmark_bubble_controller.mm +++ b/chrome/browser/cocoa/bookmark_bubble_controller.mm @@ -98,7 +98,7 @@ [BrowserWindowController browserWindowControllerForWindow:parentWindow_]; [bwc lockBarVisibilityForOwner:self withAnimation:NO delay:NO]; NSWindow* window = [self window]; // completes nib load - [bubble_ setArrowLocation:kTopLeft]; + [bubble_ setArrowLocation:kTopRight]; // Insure decent positioning even in the absence of a browser controller, // which will occur for some unit tests. NSPoint arrowtip = bwc ? [bwc pointForBubbleArrowTip] : diff --git a/chrome/browser/cocoa/browser_test_helper.h b/chrome/browser/cocoa/browser_test_helper.h index 0420c7a..b7e3e64 100644 --- a/chrome/browser/cocoa/browser_test_helper.h +++ b/chrome/browser/cocoa/browser_test_helper.h @@ -25,6 +25,15 @@ class BrowserTestHelper { profile_.reset(new TestingProfile()); profile_->CreateBookmarkModel(true); profile_->BlockUntilBookmarkModelLoaded(); + + // TODO(shess): These are needed in case someone creates a browser + // window off of browser_. pkasting indicates that other + // platforms use a stub |BrowserWindow| and thus don't need to do + // this. + // http://crbug.com/39725 + profile_->CreateAutocompleteClassifier(); + profile_->CreateTemplateURLModel(); + browser_.reset(new Browser(Browser::TYPE_NORMAL, profile_.get())); } diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm index f482990..d023663 100644 --- a/chrome/browser/cocoa/browser_window_controller.mm +++ b/chrome/browser/cocoa/browser_window_controller.mm @@ -1375,7 +1375,7 @@ } - (NSPoint)pointForBubbleArrowTip { - NSRect rect = [toolbarController_ starButtonInWindowCoordinates]; + NSRect rect = [toolbarController_ starIconInWindowCoordinates]; // Determine the point of the arrow of the bubble window. NSPoint p = rect.origin; p.x += (NSWidth(rect) / 2.0) + 1.0; // Star is not exactly in center. diff --git a/chrome/browser/cocoa/browser_window_controller_unittest.mm b/chrome/browser/cocoa/browser_window_controller_unittest.mm index 5b054fa..d6a3dca 100644 --- a/chrome/browser/cocoa/browser_window_controller_unittest.mm +++ b/chrome/browser/cocoa/browser_window_controller_unittest.mm @@ -437,10 +437,10 @@ TEST_F(BrowserWindowControllerTest, TestTopRightForBubble) { NSPoint p = [controller_ pointForBubbleArrowTip]; NSRect all = [[controller_ window] frame]; - // As a sanity check make sure the point is vaguely in the top left + // As a sanity check make sure the point is vaguely in the top right // of the window. EXPECT_GT(p.y, all.origin.y + (all.size.height/2)); - EXPECT_LT(p.x, all.origin.x + (all.size.width/2)); + EXPECT_GT(p.x, all.origin.x + (all.size.width/2)); } // By the "zoom frame", we mean what Apple calls the "standard frame". diff --git a/chrome/browser/cocoa/location_bar_view_mac.h b/chrome/browser/cocoa/location_bar_view_mac.h index 5a82d67..08e1524 100644 --- a/chrome/browser/cocoa/location_bar_view_mac.h +++ b/chrome/browser/cocoa/location_bar_view_mac.h @@ -24,7 +24,6 @@ #include "third_party/skia/include/core/SkBitmap.h" @class AutocompleteTextField; -class BubblePositioner; class CommandUpdater; class ContentSettingImageModel; @class ExtensionPopupController; @@ -41,7 +40,6 @@ class LocationBarViewMac : public AutocompleteEditController, public NotificationObserver { public: LocationBarViewMac(AutocompleteTextField* field, - const BubblePositioner* bubble_positioner, CommandUpdater* command_updater, ToolbarModel* toolbar_model, Profile* profile, @@ -64,6 +62,9 @@ class LocationBarViewMac : public AutocompleteEditController, virtual void InvalidatePageActions(); virtual void SaveStateToContents(TabContents* contents); virtual void Revert(); + virtual const AutocompleteEditView* location_entry() const { + return edit_view_.get(); + } virtual AutocompleteEditView* location_entry() { return edit_view_.get(); } @@ -76,6 +77,13 @@ class LocationBarViewMac : public AutocompleteEditController, virtual ExtensionAction* GetVisiblePageAction(size_t index); virtual void TestPageActionPressed(size_t index); + // Set/Get the editable state of the field. + void SetEditable(bool editable); + bool IsEditable(); + + // Set the starred state of the bookmark star. + void SetStarred(bool starred); + // Updates the location bar. Resets the bar's permanent text and // security style, and if |should_restore_state| is true, restores // saved state from the tab (for tab switching). @@ -124,7 +132,6 @@ class LocationBarViewMac : public AutocompleteEditController, const std::wstring& keyword, const std::wstring& short_name, const bool is_keyword_hint, - const bool show_search_hint, NSImage* image); // Overridden from NotificationObserver. @@ -142,7 +149,9 @@ class LocationBarViewMac : public AutocompleteEditController, // Sets the image. void SetImage(NSImage* image); - void SetImage(SkBitmap* image); + + // Get the |resource_id| image resource and set the image. + void SetIcon(int resource_id); // Sets the label text, font, and color. |text| may be nil; |color| and // |font| are ignored if |text| is nil. @@ -156,9 +165,21 @@ class LocationBarViewMac : public AutocompleteEditController, const NSAttributedString* GetLabel() const { return label_; } bool IsVisible() const { return visible_; } + // Default size when no image is present. + virtual NSSize GetDefaultImageSize() const; + + // Returns the size of the image, else the default size. + NSSize GetImageSize() const; + // Returns the tooltip for this image view or |nil| if there is none. virtual const NSString* GetToolTip() { return nil; } + // Used to determinate if the item can act as a drag source. + virtual bool IsDraggable() { return false; } + + // The drag pasteboard to use if a drag is initiated. + virtual NSPasteboard* GetDragPasteboard() { return nil; } + // Called on mouse down. virtual void OnMousePressed(NSRect bounds) {} @@ -176,42 +197,50 @@ class LocationBarViewMac : public AutocompleteEditController, DISALLOW_COPY_AND_ASSIGN(LocationBarImageView); }; - // SecurityImageView is used to display the lock or warning icon when the - // current URL's scheme is https. - class SecurityImageView : public LocationBarImageView { + // LocationIconView is used to display an icon to the left of the address. + class LocationIconView : public LocationBarImageView { public: - enum Image { - LOCK = 0, - WARNING - }; + explicit LocationIconView(LocationBarViewMac* owner); + virtual ~LocationIconView(); - SecurityImageView(LocationBarViewMac* owner, - Profile* profile, - ToolbarModel* model); - virtual ~SecurityImageView(); + // Is draggable if the autocomplete edit view has not be changed. + virtual bool IsDraggable(); - // Sets the image to the appropriate icon. - void SetImageShown(Image image); + // Drag the URL and title from the current tab. + virtual NSPasteboard* GetDragPasteboard(); // Shows the page info dialog. virtual void OnMousePressed(NSRect bounds); private: - // The lock icon shown when using HTTPS. Loaded lazily, the first time it's - // needed. - scoped_nsobject<NSImage> lock_icon_; - - // The warning icon shown when HTTPS is broken. Loaded lazily, the first - // time it's needed. - scoped_nsobject<NSImage> warning_icon_; - // The location bar view that owns us. LocationBarViewMac* owner_; - Profile* profile_; - ToolbarModel* model_; + DISALLOW_COPY_AND_ASSIGN(LocationIconView); + }; - DISALLOW_COPY_AND_ASSIGN(SecurityImageView); + // Used to display the bookmark star in the RHS. + class StarIconView : public LocationBarImageView { + public: + explicit StarIconView(CommandUpdater* command_updater); + virtual ~StarIconView() {} + + // Shows the bookmark bubble. + virtual void OnMousePressed(NSRect bounds); + + // Set the image and tooltip based on |starred|. + void SetStarred(bool starred); + + virtual const NSString* GetToolTip(); + + private: + // For bringing up bookmark bar. + CommandUpdater* command_updater_; // Weak, owned by Browser. + + // The string to show for a tooltip. + scoped_nsobject<NSString> tooltip_; + + DISALLOW_COPY_AND_ASSIGN(StarIconView); }; // PageActionImageView is used to display the icon for a given Page Action @@ -231,14 +260,13 @@ class LocationBarViewMac : public AutocompleteEditController, void set_preview_enabled(bool enabled) { preview_enabled_ = enabled; } - bool preview_enabled() { return preview_enabled_; } + bool preview_enabled() const { return preview_enabled_; } - // Returns the size of the image, or a default size if no image available. // When a new page action is created, all the icons are destroyed and // recreated; at this point we need to calculate sizes to lay out the // icons even though no images are available yet. For this case, we return // the default image size for a page icon. - virtual NSSize GetPreferredImageSize(); + virtual NSSize GetDefaultImageSize() const; // Either notify listeners or show a popup depending on the Page Action. virtual void OnMousePressed(NSRect bounds); @@ -384,11 +412,11 @@ class LocationBarViewMac : public AutocompleteEditController, }; private: - // Sets the SSL icon we should be showing. - void SetSecurityIcon(ToolbarModel::Icon icon); + // Sets the location icon we should be showing. + void SetIcon(int resource_id); - // Sets the label for the SSL icon. - void SetSecurityIconLabel(); + // Sets the label for the SSL state. + void SetSecurityLabel(); // Posts |notification| to the default notification center. void PostNotification(const NSString* notification); @@ -411,8 +439,14 @@ class LocationBarViewMac : public AutocompleteEditController, // The user's desired disposition for how their input should be opened. WindowOpenDisposition disposition_; - // The view that shows the lock/warning when in HTTPS mode. - SecurityImageView security_image_view_; + // A view that shows an icon to the left of the address. + LocationIconView location_icon_view_; + + // Security info as text which floats left of the page actions. + LocationBarImageView security_label_view_; + + // Bookmark star right of page actions. + StarIconView star_icon_view_; // Any installed Page Actions. PageActionViewList page_action_views_; diff --git a/chrome/browser/cocoa/location_bar_view_mac.mm b/chrome/browser/cocoa/location_bar_view_mac.mm index dde3095..35751dc 100644 --- a/chrome/browser/cocoa/location_bar_view_mac.mm +++ b/chrome/browser/cocoa/location_bar_view_mac.mm @@ -41,6 +41,7 @@ #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "skia/ext/skia_utils_mac.h" +#import "third_party/mozilla/NSPasteboard+Utils.h" // TODO(shess): This code is mostly copied from the gtk @@ -62,11 +63,13 @@ std::wstring GetKeywordName(Profile* profile, const std::wstring& keyword) { return std::wstring(); } -// Values for the green text color displayed for EV certificates, based -// on the values for kEvTextColor in location_bar_view_gtk.cc. -static const CGFloat kEvTextColorRedComponent = 0.0; -static const CGFloat kEvTextColorGreenComponent = 0.59; -static const CGFloat kEvTextColorBlueComponent = 0.08; +// Values for the label colors for different security states. +static const CGFloat kEVSecureTextColorRedComponent = 0.03; +static const CGFloat kEVSecureTextColorGreenComponent = 0.58; +static const CGFloat kEVSecureTextColorBlueComponent = 0.0; +static const CGFloat kSecurityErrorTextColorRedComponent = 0.63; +static const CGFloat kSecurityErrorTextColorGreenComponent = 0.0; +static const CGFloat kSecurityErrorTextColorBlueComponent = 0.0; // Build a short string to use in keyword-search when the field isn't // very big. @@ -91,17 +94,18 @@ std::wstring CalculateMinString(const std::wstring& description) { LocationBarViewMac::LocationBarViewMac( AutocompleteTextField* field, - const BubblePositioner* bubble_positioner, CommandUpdater* command_updater, ToolbarModel* toolbar_model, Profile* profile, Browser* browser) - : edit_view_(new AutocompleteEditViewMac(this, bubble_positioner, - toolbar_model, profile, command_updater, field)), + : edit_view_(new AutocompleteEditViewMac(this, toolbar_model, profile, + command_updater, field)), command_updater_(command_updater), field_(field), disposition_(CURRENT_TAB), - security_image_view_(this, profile, toolbar_model), + location_icon_view_(this), + security_label_view_(), + star_icon_view_(command_updater), page_action_views_(this, profile, toolbar_model), profile_(profile), browser_(browser), @@ -116,7 +120,9 @@ LocationBarViewMac::LocationBarViewMac( } AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; - [cell setSecurityImageView:&security_image_view_]; + [cell setLocationIconView:&location_icon_view_]; + [cell setSecurityLabelView:&security_label_view_]; + [cell setStarIconView:&star_icon_view_]; [cell setPageActionViewList:&page_action_views_]; [cell setContentSettingViewsList:&content_setting_views_]; @@ -129,7 +135,9 @@ LocationBarViewMac::~LocationBarViewMac() { // Disconnect from cell in case it outlives us. AutocompleteTextFieldCell* cell = [field_ autocompleteTextFieldCell]; [cell setPageActionViewList:NULL]; - [cell setSecurityImageView:NULL]; + [cell setLocationIconView:NULL]; + [cell setSecurityLabelView:NULL]; + [cell setStarIconView:NULL]; } std::wstring LocationBarViewMac::GetInputString() const { @@ -206,7 +214,7 @@ void LocationBarViewMac::SaveStateToContents(TabContents* contents) { void LocationBarViewMac::Update(const TabContents* contents, bool should_restore_state) { - SetSecurityIcon(toolbar_model_->GetIcon()); + SetIcon(edit_view_->GetIcon()); page_action_views_.RefreshViews(); RefreshContentSettingsViews(); // AutocompleteEditView restores state if the tab is non-NULL. @@ -252,7 +260,6 @@ void LocationBarViewMac::OnChangedImpl(AutocompleteTextField* field, const std::wstring& keyword, const std::wstring& short_name, const bool is_keyword_hint, - const bool show_search_hint, NSImage* image) { AutocompleteTextFieldCell* cell = [field autocompleteTextFieldCell]; const CGFloat availableWidth([field availableDecorationWidth]); @@ -298,12 +305,6 @@ void LocationBarViewMac::OnChangedImpl(AutocompleteTextField* field, [cell setKeywordHintPrefix:prefix image:image suffix:suffix availableWidth:availableWidth]; - } else if (show_search_hint) { - // Show a search hint right-justified in the field if there is no - // keyword. - const std::wstring hint(l10n_util::GetString(IDS_OMNIBOX_EMPTY_TEXT)); - [cell setSearchHintString:base::SysWideToNSString(hint) - availableWidth:availableWidth]; } else { // Nothing interesting to show, plain old text field. [cell clearKeywordAndHint]; @@ -330,7 +331,6 @@ void LocationBarViewMac::OnChanged() { keyword, short_name, edit_view_->model()->is_keyword_hint(), - edit_view_->model()->show_search_hint(), GetTabButtonImage()); } @@ -444,6 +444,22 @@ void LocationBarViewMac::TestPageActionPressed(size_t index) { page_action_views_.OnMousePressed(NSZeroRect, index); } +void LocationBarViewMac::SetEditable(bool editable) { + [field_ setEditable:editable ? YES : NO]; + star_icon_view_.SetVisible(editable); + UpdatePageActions(); +} + +bool LocationBarViewMac::IsEditable() { + return [field_ isEditable] ? true : false; +} + +void LocationBarViewMac::SetStarred(bool starred) { + star_icon_view_.SetStarred(starred); + [field_ updateCursorAndToolTipRects]; + [field_ resetFieldEditorFrameIfNeeded]; +} + NSImage* LocationBarViewMac::GetTabButtonImage() { if (!tab_button_image_) { SkBitmap* skiaBitmap = ResourceBundle::GetSharedInstance(). @@ -455,44 +471,37 @@ NSImage* LocationBarViewMac::GetTabButtonImage() { return tab_button_image_; } -void LocationBarViewMac::SetSecurityIconLabel() { - std::wstring info_text; - std::wstring info_tooltip; - ToolbarModel::InfoTextType info_text_type = - toolbar_model_->GetInfoText(&info_text, &info_tooltip); - if (info_text_type == ToolbarModel::INFO_EV_TEXT) { - NSString* icon_label = base::SysWideToNSString(info_text); - NSColor* color = [NSColor colorWithCalibratedRed:kEvTextColorRedComponent - green:kEvTextColorGreenComponent - blue:kEvTextColorBlueComponent - alpha:1.0]; - security_image_view_.SetLabel(icon_label, [field_ font], color); +void LocationBarViewMac::SetIcon(int resource_id) { + DCHECK(resource_id != 0); + + // The icon is always visible except when there is a keyword hint. + if (!edit_view_->model()->keyword().empty() && + !edit_view_->model()->is_keyword_hint()) { + location_icon_view_.SetVisible(false); } else { - security_image_view_.SetLabel(nil, nil, nil); + NSImage* image = AutocompleteEditViewMac::ImageForResource(resource_id); + location_icon_view_.SetImage(image); + location_icon_view_.SetVisible(true); + SetSecurityLabel(); } + [field_ resetFieldEditorFrameIfNeeded]; } -void LocationBarViewMac::SetSecurityIcon(ToolbarModel::Icon icon) { - switch (icon) { - case ToolbarModel::LOCK_ICON: - security_image_view_.SetImageShown(SecurityImageView::LOCK); - security_image_view_.SetVisible(true); - SetSecurityIconLabel(); - break; - case ToolbarModel::WARNING_ICON: - security_image_view_.SetImageShown(SecurityImageView::WARNING); - security_image_view_.SetVisible(true); - SetSecurityIconLabel(); - break; - case ToolbarModel::NO_ICON: - security_image_view_.SetVisible(false); - break; - default: - NOTREACHED(); - security_image_view_.SetVisible(false); - break; +void LocationBarViewMac::SetSecurityLabel() { + if (toolbar_model_->GetSecurityLevel() == ToolbarModel::EV_SECURE) { + std::wstring security_info_text(toolbar_model_->GetEVCertName()); + NSString* icon_label = base::SysWideToNSString(security_info_text); + NSColor* color = + [NSColor colorWithCalibratedRed:kEVSecureTextColorRedComponent + green:kEVSecureTextColorGreenComponent + blue:kEVSecureTextColorBlueComponent + alpha:1.0]; + security_label_view_.SetLabel(icon_label, [field_ font], color); + security_label_view_.SetVisible(true); + } else { + security_label_view_.SetLabel(nil, nil, nil); + security_label_view_.SetVisible(false); } - [field_ resetFieldEditorFrameIfNeeded]; } void LocationBarViewMac::Observe(NotificationType type, @@ -535,8 +544,9 @@ void LocationBarViewMac::LocationBarImageView::SetImage(NSImage* image) { image_.reset([image retain]); } -void LocationBarViewMac::LocationBarImageView::SetImage(SkBitmap* image) { - SetImage(gfx::SkBitmapToNSImage(*image)); +void LocationBarViewMac::LocationBarImageView::SetIcon(int resource_id) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + SetImage(rb.GetNSImageNamed(resource_id)); } void LocationBarViewMac::LocationBarImageView::SetLabel(NSString* text, @@ -564,43 +574,32 @@ void LocationBarViewMac::LocationBarImageView::SetVisible(bool visible) { visible_ = visible; } -// SecurityImageView------------------------------------------------------------ +NSSize LocationBarViewMac::LocationBarImageView::GetDefaultImageSize() const { + return NSZeroSize; +} -LocationBarViewMac::SecurityImageView::SecurityImageView( - LocationBarViewMac* owner, - Profile* profile, - ToolbarModel* model) - : lock_icon_(nil), - warning_icon_(nil), - owner_(owner), - profile_(profile), - model_(model) {} +NSSize LocationBarViewMac::LocationBarImageView::GetImageSize() const { + NSImage* image = GetImage(); + if (image) + return [image size]; + return GetDefaultImageSize(); +} -LocationBarViewMac::SecurityImageView::~SecurityImageView() {} +// LocationIconView ------------------------------------------------------------ -void LocationBarViewMac::SecurityImageView::SetImageShown(Image image) { - switch (image) { - case LOCK: - if (!lock_icon_.get()) { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - lock_icon_.reset([rb.GetNSImageNamed(IDR_LOCK) retain]); - } - SetImage(lock_icon_); - break; - case WARNING: - if (!warning_icon_.get()) { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - warning_icon_.reset([rb.GetNSImageNamed(IDR_WARNING) retain]); - } - SetImage(warning_icon_); - break; - default: - NOTREACHED(); - break; - } +LocationBarViewMac::LocationIconView::LocationIconView( + LocationBarViewMac* owner) + : owner_(owner) { } -void LocationBarViewMac::SecurityImageView::OnMousePressed(NSRect bounds) { +LocationBarViewMac::LocationIconView::~LocationIconView() {} + +void LocationBarViewMac::LocationIconView::OnMousePressed(NSRect bounds) { + // Do not show page info if the user has been editing the location + // bar, or the location bar is at the NTP. + if (owner_->location_entry()->IsEditingOrEmpty()) + return; + TabContents* tab = owner_->GetTabContents(); NavigationEntry* nav_entry = tab->controller().GetActiveEntry(); if (!nav_entry) { @@ -610,6 +609,57 @@ void LocationBarViewMac::SecurityImageView::OnMousePressed(NSRect bounds) { tab->ShowPageInfo(nav_entry->url(), nav_entry->ssl(), true); } +bool LocationBarViewMac::LocationIconView::IsDraggable() { + // Do not drag if the user has been editing the location bar, or the + // location bar is at the NTP. + if (owner_->location_entry()->IsEditingOrEmpty()) + return false; + + return true; +} + +NSPasteboard* LocationBarViewMac::LocationIconView::GetDragPasteboard() { + TabContents* tab = owner_->GetTabContents(); + DCHECK(tab); + + NSString* url = base::SysUTF8ToNSString(tab->GetURL().spec()); + NSString* title = base::SysUTF16ToNSString(tab->GetTitle()); + + NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; + [pboard declareURLPasteboardWithAdditionalTypes:[NSArray array] + owner:nil]; + [pboard setDataForURL:url title:title]; + return pboard; +} + +// StarIconView----------------------------------------------------------------- + +LocationBarViewMac::StarIconView::StarIconView(CommandUpdater* command_updater) + : command_updater_(command_updater) { + SetVisible(true); + SetStarred(false); +} + +void LocationBarViewMac::StarIconView::SetStarred(bool starred) { + if (starred) { + SetImage(AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_STAR_LIT)); + tooltip_.reset( + [l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STARRED) retain]); + } else { + SetImage(AutocompleteEditViewMac::ImageForResource(IDR_OMNIBOX_STAR)); + tooltip_.reset( + [l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STAR) retain]); + } +} + +void LocationBarViewMac::StarIconView::OnMousePressed(NSRect bounds) { + command_updater_->ExecuteCommand(IDC_BOOKMARK_PAGE); +} + +const NSString* LocationBarViewMac::StarIconView::GetToolTip() { + return tooltip_.get(); +} + // PageActionImageView---------------------------------------------------------- LocationBarViewMac::PageActionImageView::PageActionImageView( @@ -647,14 +697,9 @@ LocationBarViewMac::PageActionImageView::PageActionImageView( LocationBarViewMac::PageActionImageView::~PageActionImageView() { } -NSSize LocationBarViewMac::PageActionImageView::GetPreferredImageSize() { - NSImage* image = GetImage(); - if (image) { - return [image size]; - } else { - return NSMakeSize(Extension::kPageActionIconMaxSize, - Extension::kPageActionIconMaxSize); - } +NSSize LocationBarViewMac::PageActionImageView::GetDefaultImageSize() const { + return NSMakeSize(Extension::kPageActionIconMaxSize, + Extension::kPageActionIconMaxSize); } // Overridden from LocationBarImageView. Either notify listeners or show a @@ -868,10 +913,9 @@ void LocationBarViewMac::ContentSettingImageView::UpdateFromTabContents( const TabContents* tab_contents) { content_setting_image_model_->UpdateFromTabContents(tab_contents); if (content_setting_image_model_->is_visible()) { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); // TODO(thakis): We should use pdfs for these icons on OSX. // http://crbug.com/35847 - SetImage(rb.GetNSImageNamed(content_setting_image_model_->get_icon())); + SetIcon(content_setting_image_model_->get_icon()); SetToolTip(base::SysUTF8ToNSString( content_setting_image_model_->get_tooltip())); SetVisible(true); @@ -895,6 +939,11 @@ void LocationBarViewMac::PageActionViewList::DeleteAll() { } void LocationBarViewMac::PageActionViewList::RefreshViews() { + if (!owner_->IsEditable()) { + DeleteAll(); + return; + } + std::vector<ExtensionAction*> page_actions; ExtensionsService* service = profile_->GetExtensionsService(); if (!service) diff --git a/chrome/browser/cocoa/location_bar_view_mac_unittest.mm b/chrome/browser/cocoa/location_bar_view_mac_unittest.mm index aec948d..ecb2a7b 100644 --- a/chrome/browser/cocoa/location_bar_view_mac_unittest.mm +++ b/chrome/browser/cocoa/location_bar_view_mac_unittest.mm @@ -81,7 +81,6 @@ TEST_F(LocationBarViewMacTest, OnChangedImpl) { NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"]; const std::wstring kKeyword(L"Google"); - const NSString* kSearchHint = @"Type to search"; const NSString* kKeywordPrefix = @"Press "; const NSString* kKeywordSuffix = @" to search Google"; const NSString* kKeywordString = @"Search Google:"; @@ -90,39 +89,20 @@ TEST_F(LocationBarViewMacTest, OnChangedImpl) { [NSString stringWithFormat:@"Search Go%C:", 0x2026]; // With no special hints requested, none set. - LocationBarViewMac::OnChangedImpl( - field_, std::wstring(), std::wstring(), false, false, image); + LocationBarViewMac::OnChangedImpl(field_, std::wstring(), std::wstring(), false, image); EXPECT_FALSE([cell keywordString]); EXPECT_FALSE([cell hintString]); - // Request only a search hint. - LocationBarViewMac::OnChangedImpl( - field_, std::wstring(), std::wstring(), false, true, image); - EXPECT_FALSE([cell keywordString]); - EXPECT_TRUE([[[cell hintString] string] isEqualToString:kSearchHint]); - - // Request a keyword hint, same results whether |search_hint| - // parameter is true or false. - LocationBarViewMac::OnChangedImpl( - field_, kKeyword, kKeyword, true, true, image); - EXPECT_FALSE([cell keywordString]); - EXPECT_TRUE([[[cell hintString] string] hasPrefix:kKeywordPrefix]); - EXPECT_TRUE([[[cell hintString] string] hasSuffix:kKeywordSuffix]); - LocationBarViewMac::OnChangedImpl( - field_, kKeyword, kKeyword, true, false, image); + // Request a keyword hint. + LocationBarViewMac::OnChangedImpl(field_, kKeyword, kKeyword, true, image); EXPECT_FALSE([cell keywordString]); EXPECT_TRUE([[[cell hintString] string] hasPrefix:kKeywordPrefix]); EXPECT_TRUE([[[cell hintString] string] hasSuffix:kKeywordSuffix]); - // Request keyword-search mode, same results whether |search_hint| - // parameter is true or false. + // Request keyword-search mode. LocationBarViewMac::OnChangedImpl( - field_, kKeyword, kKeyword, false, true, image); - EXPECT_TRUE([[[cell keywordString] string] isEqualToString:kKeywordString]); - EXPECT_FALSE([cell hintString]); - LocationBarViewMac::OnChangedImpl( - field_, kKeyword, kKeyword, false, false, image); - EXPECT_TRUE([[[cell keywordString] string] isEqualToString:kKeywordString]); + field_, kKeyword, kKeyword, false, image); + EXPECT_TRUE([[[cell keywordString] string] hasSuffix:kKeywordString]); EXPECT_FALSE([cell hintString]); // Check that a partial keyword-search string is passed down in case @@ -132,14 +112,13 @@ TEST_F(LocationBarViewMacTest, OnChangedImpl) { NSRect frame([field_ frame]); frame.size.width = 10.0; [field_ setFrame:frame]; - LocationBarViewMac::OnChangedImpl( - field_, kKeyword, kKeyword, false, true, image); + LocationBarViewMac::OnChangedImpl(field_, kKeyword, kKeyword, false, image); EXPECT_TRUE([[[cell keywordString] string] isEqualToString:kPartialString]); EXPECT_FALSE([cell hintString]); // Transition back to baseline. LocationBarViewMac::OnChangedImpl( - field_, std::wstring(), std::wstring(), false, false, image); + field_, std::wstring(), std::wstring(), false, image); EXPECT_FALSE([cell keywordString]); EXPECT_FALSE([cell hintString]); } diff --git a/chrome/browser/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/cocoa/status_bubble_mac_unittest.mm index 3dd628e..6f4dab4 100644 --- a/chrome/browser/cocoa/status_bubble_mac_unittest.mm +++ b/chrome/browser/cocoa/status_bubble_mac_unittest.mm @@ -141,7 +141,7 @@ TEST_F(StatusBubbleMacTest, SetURL) { EXPECT_TRUE([GetURLText() isEqualToString:@"foopy://"]); bubble_->SetURL(GURL("http://www.cnn.com"), L""); EXPECT_TRUE(IsVisible()); - EXPECT_TRUE([GetURLText() isEqualToString:@"http://www.cnn.com/"]); + EXPECT_TRUE([GetURLText() isEqualToString:@"www.cnn.com/"]); } // Test hiding bubble that's already hidden. @@ -162,7 +162,7 @@ TEST_F(StatusBubbleMacTest, SetStatusAndURL) { EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"Status"]); bubble_->SetURL(GURL("http://www.nytimes.com/"), L""); EXPECT_TRUE(IsVisible()); - EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"http://www.nytimes.com/"]); + EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"www.nytimes.com/"]); bubble_->SetURL(GURL(), L""); EXPECT_TRUE(IsVisible()); EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"Status"]); @@ -170,13 +170,13 @@ TEST_F(StatusBubbleMacTest, SetStatusAndURL) { EXPECT_FALSE(IsVisible()); bubble_->SetURL(GURL("http://www.nytimes.com/"), L""); EXPECT_TRUE(IsVisible()); - EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"http://www.nytimes.com/"]); + EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"www.nytimes.com/"]); bubble_->SetStatus(L"Status"); EXPECT_TRUE(IsVisible()); EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"Status"]); bubble_->SetStatus(L""); EXPECT_TRUE(IsVisible()); - EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"http://www.nytimes.com/"]); + EXPECT_TRUE([GetBubbleViewText() isEqualToString:@"www.nytimes.com/"]); bubble_->SetURL(GURL(), L""); EXPECT_FALSE(IsVisible()); } diff --git a/chrome/browser/cocoa/tab_strip_controller_unittest.mm b/chrome/browser/cocoa/tab_strip_controller_unittest.mm index 0967ae4..82cea8e 100644 --- a/chrome/browser/cocoa/tab_strip_controller_unittest.mm +++ b/chrome/browser/cocoa/tab_strip_controller_unittest.mm @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. diff --git a/chrome/browser/cocoa/toolbar_controller.h b/chrome/browser/cocoa/toolbar_controller.h index 0fdd8c4..1f277c1 100644 --- a/chrome/browser/cocoa/toolbar_controller.h +++ b/chrome/browser/cocoa/toolbar_controller.h @@ -22,7 +22,6 @@ class AppMenuModel; @class BackForwardMenuController; class Browser; @class BrowserActionsController; -class BubblePositioner; class CommandUpdater; @class DelayedMenuButton; class LocationBar; @@ -70,8 +69,6 @@ class ToolbarModel; // Used for monitoring the optional toolbar button prefs. scoped_ptr<ToolbarControllerInternal::PrefObserverBridge> prefObserver_; - // Used to position the omnibox bubble. - scoped_ptr<BubblePositioner> bubblePositioner_; BooleanPrefMember showHomeButton_; BooleanPrefMember showPageOptionButtons_; BOOL hasToolbar_; // If NO, we may have only the location bar. @@ -99,7 +96,6 @@ class ToolbarModel; IBOutlet DelayedMenuButton* forwardButton_; IBOutlet NSButton* reloadButton_; IBOutlet NSButton* homeButton_; - IBOutlet NSButton* starButton_; IBOutlet NSButton* goButton_; IBOutlet MenuButton* pageButton_; IBOutlet MenuButton* wrenchButton_; @@ -147,9 +143,10 @@ class ToolbarModel; // ignored. This changes the behavior of other methods, like |-view|. - (void)setHasToolbar:(BOOL)toolbar hasLocationBar:(BOOL)locBar; -// The bookmark bubble (when you click the star) needs to know where to go. -// Somewhere near the star button seems like a good start. -- (NSRect)starButtonInWindowCoordinates; +// The bookmark bubble (when you click the star or hit Command-d) +// needs to know where to go. Somewhere near the star icon seems like +// a good start. +- (NSRect)starIconInWindowCoordinates; // Returns the desired toolbar height for the given compression factor. - (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight; @@ -171,7 +168,6 @@ class ToolbarModel; - (NSArray*)toolbarViews; - (void)showOptionalHomeButton; - (void)showOptionalPageWrenchButtons; -- (gfx::Rect)locationStackBounds; // Return a hover button for the current event. - (NSButton*)hoverButtonForEvent:(NSEvent*)theEvent; @end diff --git a/chrome/browser/cocoa/toolbar_controller.mm b/chrome/browser/cocoa/toolbar_controller.mm index 1412fc1..a9c4a33 100644 --- a/chrome/browser/cocoa/toolbar_controller.mm +++ b/chrome/browser/cocoa/toolbar_controller.mm @@ -15,7 +15,6 @@ #include "chrome/browser/autocomplete/autocomplete_edit_view.h" #include "chrome/browser/browser.h" #include "chrome/browser/browser_window.h" -#include "chrome/browser/bubble_positioner.h" #import "chrome/browser/cocoa/autocomplete_text_field.h" #import "chrome/browser/cocoa/autocomplete_text_field_editor.h" #import "chrome/browser/cocoa/back_forward_menu_controller.h" @@ -51,8 +50,6 @@ NSString* const kBackButtonImageName = @"back_Template.pdf"; NSString* const kForwardButtonImageName = @"forward_Template.pdf"; NSString* const kReloadButtonImageName = @"reload_Template.pdf"; NSString* const kHomeButtonImageName = @"home_Template.pdf"; -NSString* const kStarButtonImageName = @"star_Template.pdf"; -NSString* const kStarButtonFillingImageName = @"starred.pdf"; NSString* const kGoButtonGoImageName = @"go_Template.pdf"; NSString* const kGoButtonStopImageName = @"stop_Template.pdf"; NSString* const kPageButtonImageName = @"menu_page_Template.pdf"; @@ -87,26 +84,6 @@ const CGFloat kAnimationDuration = 0.2; - (void)adjustLocationAndGoPositionsBy:(CGFloat)dX animate:(BOOL)animate; @end -namespace { - -// A C++ class used to correctly position the omnibox. -class BubblePositionerMac : public BubblePositioner { - public: - BubblePositionerMac(ToolbarController* controller) - : controller_(controller) { } - virtual ~BubblePositionerMac() { } - - // BubblePositioner: - virtual gfx::Rect GetLocationStackBounds() const { - return [controller_ locationStackBounds]; - } - - private: - ToolbarController* controller_; // weak, owns us -}; - -} // namespace - namespace ToolbarControllerInternal { // A C++ delegate that handles enabling/disabling menu items and handling when @@ -225,7 +202,6 @@ class PrefObserverBridge : public NotificationObserver { [forwardButton_ setImage:nsimage_cache::ImageNamed(kForwardButtonImageName)]; [reloadButton_ setImage:nsimage_cache::ImageNamed(kReloadButtonImageName)]; [homeButton_ setImage:nsimage_cache::ImageNamed(kHomeButtonImageName)]; - [starButton_ setImage:nsimage_cache::ImageNamed(kStarButtonImageName)]; [goButton_ setImage:nsimage_cache::ImageNamed(kGoButtonGoImageName)]; [pageButton_ setImage:nsimage_cache::ImageNamed(kPageButtonImageName)]; [wrenchButton_ setImage:nsimage_cache::ImageNamed(kWrenchButtonImageName)]; @@ -234,9 +210,7 @@ class PrefObserverBridge : public NotificationObserver { [wrenchButton_ setShowsBorderOnlyWhileMouseInside:YES]; [self initCommandStatus:commands_]; - bubblePositioner_.reset(new BubblePositionerMac(self)); locationBarView_.reset(new LocationBarViewMac(locationBar_, - bubblePositioner_.get(), commands_, toolbarModel_, profile_, browser_)); [locationBar_ setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]]; @@ -312,10 +286,6 @@ class PrefObserverBridge : public NotificationObserver { [[homeButton_ cell] accessibilitySetOverrideValue:description forAttribute:NSAccessibilityDescriptionAttribute]; - description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_STAR); - [[starButton_ cell] - accessibilitySetOverrideValue:description - forAttribute:NSAccessibilityDescriptionAttribute]; description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_LOCATION); [[locationBar_ cell] accessibilitySetOverrideValue:description @@ -393,9 +363,6 @@ class PrefObserverBridge : public NotificationObserver { case IDC_HOME: button = homeButton_; break; - case IDC_BOOKMARK_PAGE: - button = starButton_; - break; } [button setEnabled:enabled]; } @@ -408,8 +375,6 @@ class PrefObserverBridge : public NotificationObserver { setEnabled:commands->IsCommandEnabled(IDC_FORWARD) ? YES : NO]; [reloadButton_ setEnabled:commands->IsCommandEnabled(IDC_RELOAD) ? YES : NO]; [homeButton_ setEnabled:commands->IsCommandEnabled(IDC_HOME) ? YES : NO]; - [starButton_ - setEnabled:commands->IsCommandEnabled(IDC_BOOKMARK_PAGE) ? YES : NO]; } - (void)updateToolbarWithContents:(TabContents*)tab @@ -424,23 +389,7 @@ class PrefObserverBridge : public NotificationObserver { } - (void)setStarredState:(BOOL)isStarred { - NSImage* starImage = nil; - NSString* toolTip; - if (isStarred) { - starImage = nsimage_cache::ImageNamed(kStarButtonFillingImageName); - // Cache the string since we'll need it a lot - static NSString* starredToolTip = - [l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STARRED) retain]; - toolTip = starredToolTip; - } else { - // Cache the string since we'll need it a lot - static NSString* starToolTip = - [l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_STAR) retain]; - toolTip = starToolTip; - } - - [(GradientButtonCell*)[starButton_ cell] setUnderlayImage:starImage]; - [starButton_ setToolTip:toolTip]; + locationBarView_->SetStarred(isStarred ? true : false); } - (void)setIsLoading:(BOOL)isLoading { @@ -469,7 +418,7 @@ class PrefObserverBridge : public NotificationObserver { // Make location bar not editable when in a pop-up. // TODO(viettrungluu): is this right (all the time)? - [locationBar_ setEditable:toolbar]; + locationBarView_->SetEditable(toolbar ? true : false); } - (NSView*)view { @@ -507,7 +456,7 @@ class PrefObserverBridge : public NotificationObserver { // Returns an array of views in the order of the outlets above. - (NSArray*)toolbarViews { return [NSArray arrayWithObjects:backButton_, forwardButton_, reloadButton_, - homeButton_, starButton_, goButton_, pageButton_, wrenchButton_, + homeButton_, goButton_, pageButton_, wrenchButton_, locationBar_, browserActionsContainerView_, nil]; } @@ -520,14 +469,16 @@ class PrefObserverBridge : public NotificationObserver { return frame; } -// Computes the padding between the buttons that should have a separation from -// the positions in the nib. Since the forward and reload buttons are always -// visible, we use those buttons as the canonical spacing. +// Computes the padding between the buttons that should have a +// separation from the positions in the nib. |homeButton_| is right +// of |forwardButton_| unless it has been hidden, in which case +// |reloadButton_| is in that spot. - (CGFloat)interButtonSpacing { - NSRect forwardFrame = [forwardButton_ frame]; - NSRect reloadFrame = [reloadButton_ frame]; - DCHECK(NSMinX(reloadFrame) > NSMaxX(forwardFrame)); - return NSMinX(reloadFrame) - NSMaxX(forwardFrame); + const NSRect forwardFrame = [forwardButton_ frame]; + NSButton* nextButton = [homeButton_ isHidden] ? reloadButton_ : homeButton_; + const NSRect nextButtonFrame = [nextButton frame]; + DCHECK_GT(NSMinX(nextButtonFrame), NSMaxX(forwardFrame)); + return NSMinX(nextButtonFrame) - NSMaxX(forwardFrame); } // Show or hide the home button based on the pref. @@ -546,7 +497,7 @@ class PrefObserverBridge : public NotificationObserver { if (hide) moveX *= -1; // Reverse the direction of the move. - [starButton_ setFrame:NSOffsetRect([starButton_ frame], moveX, 0)]; + [reloadButton_ setFrame:NSOffsetRect([reloadButton_ frame], moveX, 0)]; [locationBar_ setFrame:[self adjustRect:[locationBar_ frame] byAmount:moveX]]; [homeButton_ setHidden:hide]; @@ -769,8 +720,8 @@ class PrefObserverBridge : public NotificationObserver { [NSAnimationContext endGrouping]; } -- (NSRect)starButtonInWindowCoordinates { - return [starButton_ convertRect:[starButton_ bounds] toView:nil]; +- (NSRect)starIconInWindowCoordinates { + return [locationBar_ convertRect:[locationBar_ starIconFrame] toView:nil]; } - (CGFloat)desiredHeightForCompression:(CGFloat)compressByHeight { @@ -845,31 +796,6 @@ class PrefObserverBridge : public NotificationObserver { } -- (gfx::Rect)locationStackBounds { - // The number of pixels from the left or right edges of the location stack to - // "just inside the visible borders". When the omnibox bubble contents are - // aligned with this, the visible borders tacked on to the outsides will line - // up with the visible borders on the location stack. - const int kLocationStackEdgeWidth = 2; - - const NSRect locationFrame = [locationBar_ frame]; - - // Expand to include star and go buttons. Including the widths - // rather that calculating from their current placement because this - // method can be called while the resize is still rearranging the - // views involved. - const CGFloat minX = NSMinX(locationFrame) - NSWidth([starButton_ frame]); - const CGFloat maxX = NSMaxX(locationFrame) + NSWidth([goButton_ frame]); - - NSRect r = NSMakeRect(minX, NSMinY(locationFrame), maxX - minX, - NSHeight(locationFrame)); - gfx::Rect stack_bounds( - NSRectToCGRect([[self view] convertRect:r toView:nil])); - // Inset the bounds to just inside the visible edges (see comment above). - stack_bounds.Inset(kLocationStackEdgeWidth, 0); - return stack_bounds; -} - // (URLDropTargetController protocol) - (void)dropURLs:(NSArray*)urls inView:(NSView*)view at:(NSPoint)point { // TODO(viettrungluu): This code is more or less copied from the code in diff --git a/chrome/browser/cocoa/toolbar_controller_unittest.mm b/chrome/browser/cocoa/toolbar_controller_unittest.mm index 7c718c4..dcea565 100644 --- a/chrome/browser/cocoa/toolbar_controller_unittest.mm +++ b/chrome/browser/cocoa/toolbar_controller_unittest.mm @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -43,7 +43,7 @@ class ToolbarControllerTest : public CocoaTest { // Indexes that match the ordering returned by the private ToolbarController // |-toolbarViews| method. enum { - kBackIndex, kForwardIndex, kReloadIndex, kHomeIndex, kStarIndex, kGoIndex, + kBackIndex, kForwardIndex, kReloadIndex, kHomeIndex, kGoIndex, kPageIndex, kWrenchIndex, kLocationIndex, kBrowserActionContainerViewIndex }; @@ -78,8 +78,6 @@ class ToolbarControllerTest : public CocoaTest { [[views objectAtIndex:kReloadIndex] isEnabled] ? true : false); EXPECT_EQ(updater->IsCommandEnabled(IDC_HOME), [[views objectAtIndex:kHomeIndex] isEnabled] ? true : false); - EXPECT_EQ(updater->IsCommandEnabled(IDC_BOOKMARK_PAGE), - [[views objectAtIndex:kStarIndex] isEnabled] ? true : false); } BrowserTestHelper helper_; @@ -160,16 +158,16 @@ TEST_F(ToolbarControllerTest, ToggleHome) { NSView* homeButton = [[bar_ toolbarViews] objectAtIndex:kHomeIndex]; EXPECT_EQ(showHome, ![homeButton isHidden]); - NSView* starButton = [[bar_ toolbarViews] objectAtIndex:kStarIndex]; + NSView* reloadButton = [[bar_ toolbarViews] objectAtIndex:kReloadIndex]; NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex]; - NSRect originalStarFrame = [starButton frame]; + NSRect originalReloadFrame = [reloadButton frame]; NSRect originalLocationBarFrame = [locationBar frame]; // Toggle the pref and make sure the button changed state and the other // views moved. prefs->SetBoolean(prefs::kShowHomeButton, !showHome); EXPECT_EQ(showHome, [homeButton isHidden]); - EXPECT_NE(NSMinX(originalStarFrame), NSMinX([starButton frame])); + EXPECT_NE(NSMinX(originalReloadFrame), NSMinX([reloadButton frame])); EXPECT_NE(NSMinX(originalLocationBarFrame), NSMinX([locationBar frame])); EXPECT_NE(NSWidth(originalLocationBarFrame), NSWidth([locationBar frame])); } @@ -220,32 +218,14 @@ TEST_F(ToolbarControllerTest, DontToggleWhenNoToolbar) { EXPECT_TRUE(NSEqualRects(locationBarFrame, newLocationBarFrame)); } -TEST_F(ToolbarControllerTest, StarButtonInWindowCoordinates) { - NSRect star = [bar_ starButtonInWindowCoordinates]; +TEST_F(ToolbarControllerTest, StarIconInWindowCoordinates) { + NSRect star = [bar_ starIconInWindowCoordinates]; NSRect all = [[[bar_ view] window] frame]; // Make sure the star is completely inside the window rect EXPECT_TRUE(NSContainsRect(all, star)); } -TEST_F(ToolbarControllerTest, BubblePosition) { - NSView* locationBar = [[bar_ toolbarViews] objectAtIndex:kLocationIndex]; - - // The window frame (in window base coordinates). - NSRect all = [[[bar_ view] window] frame]; - // The frame of the location bar in window base coordinates. - NSRect locationFrame = - [locationBar convertRect:[locationBar bounds] toView:nil]; - // The frame of the location stack in window base coordinates. The horizontal - // coordinates here are used for the omnibox dropdown. - gfx::Rect locationStackFrame = [bar_ locationStackBounds]; - - // Make sure the location stack starts to the left of and ends to the right of - // the location bar. - EXPECT_LT(locationStackFrame.x(), NSMinX(locationFrame)); - EXPECT_GT(locationStackFrame.right(), NSMaxX(locationFrame)); -} - TEST_F(ToolbarControllerTest, HoverButtonForEvent) { scoped_nsobject<HitView> view([[HitView alloc] initWithFrame:NSMakeRect(0,0,100,100)]); |