diff options
| author | Ben Murdoch <benm@google.com> | 2010-11-18 18:32:45 +0000 |
|---|---|---|
| committer | Ben Murdoch <benm@google.com> | 2010-11-18 18:38:07 +0000 |
| commit | 513209b27ff55e2841eac0e4120199c23acce758 (patch) | |
| tree | aeba30bb08c5f47c57003544e378a377c297eee6 /chrome/browser/cocoa/page_info_bubble_controller.mm | |
| parent | 164f7496de0fbee436b385a79ead9e3cb81a50c1 (diff) | |
| download | external_chromium-513209b27ff55e2841eac0e4120199c23acce758.zip external_chromium-513209b27ff55e2841eac0e4120199c23acce758.tar.gz external_chromium-513209b27ff55e2841eac0e4120199c23acce758.tar.bz2 | |
Merge Chromium at r65505: Initial merge by git.
Change-Id: I31d8f1d8cd33caaf7f47ffa7350aef42d5fbdb45
Diffstat (limited to 'chrome/browser/cocoa/page_info_bubble_controller.mm')
| -rw-r--r-- | chrome/browser/cocoa/page_info_bubble_controller.mm | 171 |
1 files changed, 109 insertions, 62 deletions
diff --git a/chrome/browser/cocoa/page_info_bubble_controller.mm b/chrome/browser/cocoa/page_info_bubble_controller.mm index a2cc34f..c2c2d36 100644 --- a/chrome/browser/cocoa/page_info_bubble_controller.mm +++ b/chrome/browser/cocoa/page_info_bubble_controller.mm @@ -6,7 +6,9 @@ #include "app/l10n_util.h" #include "app/l10n_util_mac.h" +#include "base/message_loop.h" #include "base/sys_string_conversions.h" +#include "base/task.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/cert_store.h" #include "chrome/browser/certificate_viewer.h" @@ -26,9 +28,9 @@ - (PageInfoModel*)model; - (NSButton*)certificateButtonWithFrame:(NSRect)frame; - (void)configureTextFieldAsLabel:(NSTextField*)textField; -- (CGFloat)addTitleViewForInfo:(const PageInfoModel::SectionInfo&)info - toSubviews:(NSMutableArray*)subviews - atPoint:(NSPoint)point; +- (CGFloat)addHeadlineViewForInfo:(const PageInfoModel::SectionInfo&)info + toSubviews:(NSMutableArray*)subviews + atPoint:(NSPoint)point; - (CGFloat)addDescriptionViewForInfo:(const PageInfoModel::SectionInfo&)info toSubviews:(NSMutableArray*)subviews atPoint:(NSPoint)point; @@ -45,6 +47,19 @@ parentWindow:(NSWindow*)parent; @end +// This simple NSView subclass is used as the single subview of the page info +// bubble's window's contentView. Drawing is flipped so that layout of the +// sections is easier. Apple recommends flipping the coordinate origin when +// doing a lot of text layout because it's more natural. +@interface PageInfoContentView : NSView { +} +@end +@implementation PageInfoContentView +- (BOOL)isFlipped { + return YES; +} +@end + namespace { // The width of the window, in view coordinates. The height will be determined @@ -57,8 +72,8 @@ const NSInteger kVerticalSpacing = 10; // Padding along on the X-axis between the window frame and content. const NSInteger kFramePadding = 20; -// Spacing between the title and description text views. -const NSInteger kTitleSpacing = 2; +// Spacing between the optional headline and description text views. +const NSInteger kHeadlineSpacing = 2; // Spacing between the image and the text. const NSInteger kImageSpacing = 10; @@ -75,20 +90,33 @@ const CGFloat kTextXPosition = kTextXPositionNoImage + kImageSize + const CGFloat kTextWidth = kWindowWidth - (kImageSize + kImageSpacing + kFramePadding * 2); - // Bridge that listens for change notifications from the model. class PageInfoModelBubbleBridge : public PageInfoModel::PageInfoModelObserver { public: - PageInfoModelBubbleBridge() : controller_(nil) {} + PageInfoModelBubbleBridge() + : controller_(nil), + ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) { + } // PageInfoModelObserver implementation. virtual void ModelChanged() { + // Check to see if a layout has already been scheduled. + if (!task_factory_.empty()) + return; + // Delay performing layout by a second so that all the animations from // InfoBubbleWindow and origin updates from BaseBubbleController finish, so // that we don't all race trying to change the frame's origin. - [controller_ performSelector:@selector(performLayout) - withObject:nil - afterDelay:1.0]; + // + // Using ScopedRunnableMethodFactory is superior here to |-performSelector:| + // because it will not retain its target; if the child outlives its parent, + // zombies get left behind (http://crbug.com/59619). This will also cancel + // the scheduled Tasks if the controller (and thus this bridge) get + // destroyed before the message can be delivered. + MessageLoop::current()->PostDelayedTask(FROM_HERE, + task_factory_.NewRunnableMethod( + &PageInfoModelBubbleBridge::PerformLayout), + 1000 /* milliseconds */); } // Sets the controller. @@ -97,7 +125,14 @@ class PageInfoModelBubbleBridge : public PageInfoModel::PageInfoModelObserver { } private: + void PerformLayout() { + [controller_ performLayout]; + } + PageInfoBubbleController* controller_; // weak + + // Factory that vends RunnableMethod tasks for scheduling layout. + ScopedRunnableMethodFactory<PageInfoModelBubbleBridge> task_factory_; }; } // namespace @@ -173,28 +208,33 @@ void ShowPageInfoBubble(gfx::NativeWindow parent, // not using HTTPS. - (void)performLayout { // |offset| is the Y position that should be drawn at next. - CGFloat offset = kVerticalSpacing; + CGFloat offset = kFramePadding; // Keep the new subviews in an array that gets replaced at the end. NSMutableArray* subviews = [NSMutableArray array]; - // First item, drawn at the bottom of the window, is the help center link. - offset += [self addHelpButtonToSubviews:subviews atOffset:offset]; - offset += kVerticalSpacing; - offset += [self addSeparatorToSubviews:subviews atOffset:offset]; - - // Build the window from bottom-up because Cocoa's coordinate origin is the - // lower left. - for (int i = model_->GetSectionCount() - 1; i >= 0; --i) { + // The subviews will be attached to the PageInfoContentView, which has a + // flipped origin. This allows the code to build top-to-bottom. + const int sectionCount = model_->GetSectionCount(); + for (int i = 0; i < sectionCount; ++i) { PageInfoModel::SectionInfo info = model_->GetSectionInfo(i); // Only certain sections have images. This affects the X position. BOOL hasImage = model_->GetIconImage(info.icon_id) != nil; CGFloat xPosition = (hasImage ? kTextXPosition : kTextXPositionNoImage); - if (info.type == PageInfoModel::SECTION_INFO_IDENTITY) { - offset += [self addCertificateButtonToSubviews:subviews - atOffset:offset]; + // Insert the image subview for sections that are appropriate. + CGFloat imageBaseline = offset + kImageSize; + if (hasImage) { + [self addImageViewForInfo:info toSubviews:subviews atOffset:offset]; + } + + // Add the title. + if (!info.headline.empty()) { + offset += [self addHeadlineViewForInfo:info + toSubviews:subviews + atPoint:NSMakePoint(xPosition, offset)]; + offset += kHeadlineSpacing; } // Create the description of the state. @@ -202,31 +242,37 @@ void ShowPageInfoBubble(gfx::NativeWindow parent, toSubviews:subviews atPoint:NSMakePoint(xPosition, offset)]; - // Add the title. - offset += kTitleSpacing; - offset += [self addTitleViewForInfo:info - toSubviews:subviews - atPoint:NSMakePoint(xPosition, offset)]; - - // Insert the image subview for sections that are appropriate. - if (hasImage) { - [self addImageViewForInfo:info toSubviews:subviews atOffset:offset]; + if (info.type == PageInfoModel::SECTION_INFO_IDENTITY && certID_) { + offset += kVerticalSpacing; + offset += [self addCertificateButtonToSubviews:subviews atOffset:offset]; } + // If at this point the description and optional headline and button are + // not as tall as the image, adjust the offset by the difference. + CGFloat imageBaselineDelta = imageBaseline - offset; + if (imageBaselineDelta > 0) + offset += imageBaselineDelta; + // Add the separators. - if (i != 0) { - offset += kVerticalSpacing; - offset += [self addSeparatorToSubviews:subviews atOffset:offset]; - } + offset += kVerticalSpacing; + offset += [self addSeparatorToSubviews:subviews atOffset:offset]; } - // Replace the window's content. - [[[self window] contentView] setSubviews:subviews]; + // The last item at the bottom of the window is the help center link. + offset += [self addHelpButtonToSubviews:subviews atOffset:offset]; + offset += kVerticalSpacing; - offset += kFramePadding; + // Create the dummy view that uses flipped coordinates. + NSRect contentFrame = NSMakeRect(0, 0, kWindowWidth, offset); + scoped_nsobject<PageInfoContentView> contentView( + [[PageInfoContentView alloc] initWithFrame:contentFrame]); + [contentView setSubviews:subviews]; - NSRect windowFrame = NSMakeRect(0, 0, kWindowWidth, 0); - windowFrame.size.height += offset; + // Replace the window's content. + [[[self window] contentView] setSubviews: + [NSArray arrayWithObject:contentView]]; + + NSRect windowFrame = NSMakeRect(0, 0, kWindowWidth, offset); windowFrame.size = [[[self window] contentView] convertSize:windowFrame.size toView:nil]; // Adjust the origin by the difference in height. @@ -273,21 +319,21 @@ void ShowPageInfoBubble(gfx::NativeWindow parent, // Adds the title text field at the given x,y position, and returns the y // position for the next element. -- (CGFloat)addTitleViewForInfo:(const PageInfoModel::SectionInfo&)info - toSubviews:(NSMutableArray*)subviews - atPoint:(NSPoint)point { +- (CGFloat)addHeadlineViewForInfo:(const PageInfoModel::SectionInfo&)info + toSubviews:(NSMutableArray*)subviews + atPoint:(NSPoint)point { NSRect frame = NSMakeRect(point.x, point.y, kTextWidth, kImageSpacing); - scoped_nsobject<NSTextField> titleField( + scoped_nsobject<NSTextField> textField( [[NSTextField alloc] initWithFrame:frame]); - [self configureTextFieldAsLabel:titleField.get()]; - [titleField setStringValue:base::SysUTF16ToNSString(info.title)]; + [self configureTextFieldAsLabel:textField.get()]; + [textField setStringValue:base::SysUTF16ToNSString(info.headline)]; NSFont* font = [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]]; - [titleField setFont:font]; + [textField setFont:font]; frame.size.height += [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField: - titleField]; - [titleField setFrame:frame]; - [subviews addObject:titleField.get()]; + textField]; + [textField setFrame:frame]; + [subviews addObject:textField.get()]; return NSHeight(frame); } @@ -315,6 +361,9 @@ void ShowPageInfoBubble(gfx::NativeWindow parent, // Returns the y position for the next element. - (CGFloat)addCertificateButtonToSubviews:(NSMutableArray*)subviews atOffset:(CGFloat)offset { + // The certificate button should only be added if there is SSL information. + DCHECK(certID_); + // Create the certificate button. The frame will be fixed up by GTM, so // use arbitrary values. NSRect frame = NSMakeRect(kTextXPosition, offset, 100, 14); @@ -323,19 +372,17 @@ void ShowPageInfoBubble(gfx::NativeWindow parent, [GTMUILocalizerAndLayoutTweaker sizeToFitView:certButton]; // By default, assume that we don't have certificate information to show. - [certButton setEnabled:NO]; - if (certID_) { - scoped_refptr<net::X509Certificate> cert; - CertStore::GetSharedInstance()->RetrieveCert(certID_, &cert); - - // Don't bother showing certificates if there isn't one. Gears runs - // with no OS root certificate. - if (cert.get() && cert->os_cert_handle()) { - [certButton setEnabled:YES]; - } + scoped_refptr<net::X509Certificate> cert; + CertStore::GetSharedInstance()->RetrieveCert(certID_, &cert); + + // Don't bother showing certificates if there isn't one. Gears runs + // with no OS root certificate. + if (!cert.get() || !cert->os_cert_handle()) { + // This should only ever happen in unit tests. + [certButton setEnabled:NO]; } - return NSHeight(frame) + kVerticalSpacing; + return NSHeight([certButton frame]); } // Adds the state image at a pre-determined x position and the given y. This @@ -344,7 +391,7 @@ void ShowPageInfoBubble(gfx::NativeWindow parent, - (void)addImageViewForInfo:(const PageInfoModel::SectionInfo&)info toSubviews:(NSMutableArray*)subviews atOffset:(CGFloat)offset { - NSRect frame = NSMakeRect(kFramePadding, offset - kImageSize, kImageSize, + NSRect frame = NSMakeRect(kFramePadding, offset, kImageSize, kImageSize); scoped_nsobject<NSImageView> imageView( [[NSImageView alloc] initWithFrame:frame]); |
