| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.h" | 5 #include "chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.h" |
| 6 | 6 |
| 7 #import "base/mac/foundation_util.h" | 7 #import "base/mac/foundation_util.h" |
| 8 #include "components/grit/components_scaled_resources.h" | 8 #include "components/grit/components_scaled_resources.h" |
| 9 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTw
eaker.h" | 9 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTw
eaker.h" |
| 10 #import "ui/base/cocoa/controls/blue_label_button.h" | 10 #import "ui/base/cocoa/controls/blue_label_button.h" |
| 11 #import "ui/base/cocoa/controls/hyperlink_text_view.h" |
| 11 #import "ui/base/cocoa/nscolor_additions.h" | 12 #import "ui/base/cocoa/nscolor_additions.h" |
| 12 #include "ui/base/l10n/l10n_util_mac.h" | 13 #include "ui/base/l10n/l10n_util_mac.h" |
| 13 #include "ui/base/resource/resource_bundle.h" | 14 #include "ui/base/resource/resource_bundle.h" |
| 14 | 15 |
| 15 namespace { | 16 namespace { |
| 16 | 17 |
| 17 // Maximum width used by page contents. | 18 // Maximum width used by page contents. |
| 18 const CGFloat kMaxContainerWidth = 600; | 19 const CGFloat kMaxContainerWidth = 600; |
| 19 // Padding between icon and title. | 20 // Padding between icon and title. |
| 20 const CGFloat kIconTitleSpacing = 40; | 21 const CGFloat kIconTitleSpacing = 40; |
| 21 // Padding between title and message. | 22 // Padding between title and message. |
| 22 const CGFloat kTitleMessageSpacing = 18; | 23 const CGFloat kTitleMessageSpacing = 18; |
| 23 // Padding between message and link. | 24 // Padding between message and link. |
| 24 const CGFloat kMessageLinkSpacing = 50; | 25 const CGFloat kMessageLinkSpacing = 50; |
| 25 // Padding between message and button. | 26 // Padding between message and button. |
| 26 const CGFloat kMessageButtonSpacing = 44; | 27 const CGFloat kMessageButtonSpacing = 44; |
| 27 // Minimum margins on all sides. | 28 // Minimum margins on all sides. |
| 28 const CGFloat kTabMargin = 13; | 29 const CGFloat kTabMargin = 13; |
| 29 // Maximum margin on top. | 30 // Maximum margin on top. |
| 30 const CGFloat kMaxTopMargin = 130; | 31 const CGFloat kMaxTopMargin = 130; |
| 31 | 32 |
| 32 NSTextField* MakeLabelTextField(NSRect frame) { | 33 NSTextField* MakeLabelTextField(NSRect frame) { |
| 34 // Not a scoped_nsobject for easy property access. |
| 33 NSTextField* ret = [[[NSTextField alloc] initWithFrame:frame] autorelease]; | 35 NSTextField* ret = [[[NSTextField alloc] initWithFrame:frame] autorelease]; |
| 34 ret.autoresizingMask = NSViewWidthSizable | NSViewMaxYMargin; | 36 ret.autoresizingMask = NSViewWidthSizable; |
| 35 ret.editable = NO; | 37 ret.editable = NO; |
| 36 ret.drawsBackground = NO; | 38 ret.drawsBackground = NO; |
| 37 ret.bezeled = NO; | 39 ret.bezeled = NO; |
| 38 return ret; | 40 return ret; |
| 39 } | 41 } |
| 40 | 42 |
| 41 } // namespace | 43 } // namespace |
| 42 | 44 |
| 43 @interface SadTabContainerView : NSView | 45 @interface SadTabContainerView : NSView |
| 44 @end | 46 @end |
| 45 | 47 |
| 46 @implementation SadTabContainerView | 48 @implementation SadTabContainerView |
| 47 - (BOOL)isFlipped { | 49 - (BOOL)isFlipped { |
| 48 return YES; | 50 return YES; |
| 49 } | 51 } |
| 50 @end | 52 @end |
| 51 | 53 |
| 52 @interface SadTabView ()<NSTextViewDelegate> | 54 @interface SadTabView ()<NSTextViewDelegate> |
| 53 @end | 55 @end |
| 54 | 56 |
| 55 @implementation SadTabView { | 57 @implementation SadTabView { |
| 56 NSView* container_; | 58 NSView* container_; |
| 57 NSImageView* icon_; | |
| 58 NSTextField* title_; | |
| 59 NSTextField* message_; | 59 NSTextField* message_; |
| 60 HyperlinkTextView* help_; | 60 HyperlinkTextView* help_; |
| 61 NSButton* button_; | 61 NSButton* button_; |
| 62 chrome::SadTab* sadTab_; |
| 62 } | 63 } |
| 63 | 64 |
| 64 @synthesize delegate = delegate_; | 65 - (instancetype)initWithFrame:(NSRect)frame sadTab:(chrome::SadTab*)sadTab { |
| 66 if ((self = [super initWithFrame:frame])) { |
| 67 sadTab_ = sadTab; |
| 65 | 68 |
| 66 - (instancetype)initWithFrame:(NSRect)frame { | |
| 67 if ((self = [super initWithFrame:frame])) { | |
| 68 self.wantsLayer = YES; | 69 self.wantsLayer = YES; |
| 69 self.layer.backgroundColor = | 70 self.layer.backgroundColor = |
| 70 [NSColor colorWithCalibratedWhite:245.0f / 255.0f alpha:1.0].cr_CGColor; | 71 [NSColor colorWithCalibratedWhite:245.0f / 255.0f alpha:1.0].cr_CGColor; |
| 71 container_ = [[SadTabContainerView new] autorelease]; | 72 container_ = [[SadTabContainerView new] autorelease]; |
| 72 | 73 |
| 73 NSImage* iconImage = ResourceBundle::GetSharedInstance() | 74 NSImage* iconImage = ResourceBundle::GetSharedInstance() |
| 74 .GetNativeImageNamed(IDR_CRASH_SAD_TAB) | 75 .GetNativeImageNamed(IDR_CRASH_SAD_TAB) |
| 75 .ToNSImage(); | 76 .ToNSImage(); |
| 76 icon_ = [[NSImageView new] autorelease]; | 77 NSImageView* icon = [[NSImageView new] autorelease]; |
| 77 icon_.image = iconImage; | 78 icon.image = iconImage; |
| 78 icon_.frameSize = iconImage.size; | 79 icon.frameSize = iconImage.size; |
| 79 icon_.autoresizingMask = NSViewMaxXMargin | NSViewMaxYMargin; | 80 [container_ addSubview:icon]; |
| 80 [container_ addSubview:icon_]; | |
| 81 | 81 |
| 82 CGFloat width = self.bounds.size.width; | 82 NSTextField* title = MakeLabelTextField( |
| 83 title_ = MakeLabelTextField( | 83 NSMakeRect(0, NSMaxY(icon.frame) + kIconTitleSpacing, 0, 0)); |
| 84 NSMakeRect(0, NSMaxY(icon_.frame) + kIconTitleSpacing, width, 0)); | 84 title.font = [NSFont systemFontOfSize:24]; |
| 85 title_.font = [NSFont systemFontOfSize:24]; | 85 title.textColor = |
| 86 title_.textColor = | |
| 87 [NSColor colorWithCalibratedWhite:38.0f / 255.0f alpha:1.0]; | 86 [NSColor colorWithCalibratedWhite:38.0f / 255.0f alpha:1.0]; |
| 88 [title_ sizeToFit]; | |
| 89 [container_ addSubview:title_]; | |
| 90 | 87 |
| 91 message_ = | 88 NSMutableParagraphStyle* titleStyle = |
| 92 MakeLabelTextField(NSMakeRect(0, NSMaxY(title_.frame), width, 0)); | 89 [[NSMutableParagraphStyle new] autorelease]; |
| 90 titleStyle.lineSpacing = 6; |
| 91 title.attributedStringValue = [[[NSAttributedString alloc] |
| 92 initWithString:l10n_util::GetNSString(sadTab->GetTitle()) |
| 93 attributes:@{NSParagraphStyleAttributeName : titleStyle}] |
| 94 autorelease]; |
| 95 |
| 96 [title sizeToFit]; |
| 97 [container_ addSubview:title]; |
| 98 |
| 99 NSFont* messageFont = [NSFont systemFontOfSize:14]; |
| 100 NSColor* messageColor = |
| 101 [NSColor colorWithCalibratedWhite:81.0f / 255.0f alpha:1.0]; |
| 102 |
| 103 message_ = MakeLabelTextField(NSMakeRect(0, NSMaxY(title.frame), 0, 0)); |
| 104 message_.frameOrigin = |
| 105 NSMakePoint(0, NSMaxY(title.frame) + kTitleMessageSpacing); |
| 93 base::mac::ObjCCast<NSCell>(message_.cell).wraps = YES; | 106 base::mac::ObjCCast<NSCell>(message_.cell).wraps = YES; |
| 94 message_.font = [NSFont systemFontOfSize:14]; | 107 message_.font = messageFont; |
| 95 message_.textColor = | 108 message_.textColor = messageColor; |
| 96 [NSColor colorWithCalibratedWhite:81.0f / 255.0f alpha:1.0]; | 109 message_.stringValue = l10n_util::GetNSString(sadTab->GetMessage()); |
| 97 [container_ addSubview:message_]; | 110 [container_ addSubview:message_]; |
| 98 | 111 |
| 112 NSString* helpLinkTitle = |
| 113 l10n_util::GetNSString(sadTab->GetHelpLinkTitle()); |
| 99 help_ = [[[HyperlinkTextView alloc] | 114 help_ = [[[HyperlinkTextView alloc] |
| 100 initWithFrame:NSMakeRect(0, 0, 1, message_.font.pointSize + 4)] | 115 initWithFrame:NSMakeRect(0, 0, 1, message_.font.pointSize + 4)] |
| 101 autorelease]; | 116 autorelease]; |
| 102 help_.delegate = self; | 117 help_.delegate = self; |
| 103 help_.autoresizingMask = NSViewWidthSizable | NSViewMaxYMargin; | 118 help_.autoresizingMask = NSViewWidthSizable; |
| 104 help_.textContainer.lineFragmentPadding = 2; // To align with message_. | 119 help_.textContainer.lineFragmentPadding = 2; // To align with message_. |
| 120 [help_ setMessage:helpLinkTitle |
| 121 withFont:messageFont |
| 122 messageColor:messageColor]; |
| 123 [help_ addLinkRange:NSMakeRange(0, helpLinkTitle.length) |
| 124 withURL:@(sadTab->GetHelpLinkURL()) |
| 125 linkColor:messageColor]; |
| 126 [help_ sizeToFit]; |
| 105 [container_ addSubview:help_]; | 127 [container_ addSubview:help_]; |
| 106 | 128 |
| 107 button_ = [[BlueLabelButton new] autorelease]; | 129 button_ = [[BlueLabelButton new] autorelease]; |
| 108 button_.target = self; | 130 button_.target = self; |
| 109 button_.action = @selector(buttonClicked); | 131 button_.action = @selector(buttonClicked); |
| 132 button_.title = l10n_util::GetNSString(sadTab->GetButtonTitle()); |
| 133 [button_ sizeToFit]; |
| 110 [container_ addSubview:button_]; | 134 [container_ addSubview:button_]; |
| 111 | 135 |
| 112 [self addSubview:container_]; | 136 [self addSubview:container_]; |
| 137 [self resizeSubviewsWithOldSize:self.bounds.size]; |
| 113 } | 138 } |
| 114 return self; | 139 return self; |
| 115 } | 140 } |
| 116 | 141 |
| 142 - (BOOL)isOpaque { |
| 143 return YES; |
| 144 } |
| 145 |
| 117 - (BOOL)isFlipped { | 146 - (BOOL)isFlipped { |
| 118 return YES; | 147 return YES; |
| 119 } | 148 } |
| 120 | 149 |
| 150 - (void)updateLayer { |
| 151 // Currently, updateLayer is only called once. If that changes, a DCHECK in |
| 152 // SadTab::RecordFirstPaint will pipe up and we should add a guard here. |
| 153 sadTab_->RecordFirstPaint(); |
| 154 } |
| 155 |
| 121 - (void)resizeSubviewsWithOldSize:(NSSize)oldSize { | 156 - (void)resizeSubviewsWithOldSize:(NSSize)oldSize { |
| 122 [super resizeSubviewsWithOldSize:oldSize]; | 157 [super resizeSubviewsWithOldSize:oldSize]; |
| 123 | 158 |
| 124 NSSize size = self.bounds.size; | 159 NSSize size = self.bounds.size; |
| 125 NSSize containerSize = NSMakeSize( | 160 NSSize containerSize = NSMakeSize( |
| 126 std::min(size.width - 2 * kTabMargin, kMaxContainerWidth), size.height); | 161 std::min(size.width - 2 * kTabMargin, kMaxContainerWidth), size.height); |
| 127 | 162 |
| 128 // Set the container's size first because text wrapping depends on its width. | 163 // Set the container's size first because text wrapping depends on its width. |
| 129 container_.frameSize = containerSize; | 164 container_.frameSize = containerSize; |
| 130 | 165 |
| 131 // |message_| can wrap to variable number of lines. | 166 // |message_| can wrap to variable number of lines. |
| 132 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:message_]; | 167 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:message_]; |
| 133 | 168 |
| 134 message_.frameOrigin = | |
| 135 NSMakePoint(0, NSMaxY(title_.frame) + kTitleMessageSpacing); | |
| 136 help_.frameOrigin = | 169 help_.frameOrigin = |
| 137 NSMakePoint(0, NSMaxY(message_.frame) + kMessageLinkSpacing); | 170 NSMakePoint(0, NSMaxY(message_.frame) + kMessageLinkSpacing); |
| 138 | 171 |
| 139 button_.frameOrigin = | 172 button_.frameOrigin = |
| 140 NSMakePoint(containerSize.width - NSWidth(button_.bounds), | 173 NSMakePoint(containerSize.width - NSWidth(button_.bounds), |
| 141 NSMaxY(message_.frame) + kMessageButtonSpacing); | 174 NSMaxY(message_.frame) + kMessageButtonSpacing); |
| 142 | 175 |
| 143 containerSize.height = NSMaxY(button_.frame); | 176 containerSize.height = NSMaxY(button_.frame); |
| 144 container_.frameSize = containerSize; | 177 container_.frameSize = containerSize; |
| 145 | 178 |
| 146 // Center. Top margin is must be between kTabMargin and kMaxTopMargin. | 179 // Center. Top margin is must be between kTabMargin and kMaxTopMargin. |
| 147 container_.frameOrigin = NSMakePoint( | 180 container_.frameOrigin = NSMakePoint( |
| 148 floor((size.width - containerSize.width) / 2), | 181 floor((size.width - containerSize.width) / 2), |
| 149 std::min(kMaxTopMargin, | 182 std::min(kMaxTopMargin, |
| 150 std::max(kTabMargin, | 183 std::max(kTabMargin, |
| 151 size.height - containerSize.height - kTabMargin))); | 184 size.height - containerSize.height - kTabMargin))); |
| 152 } | 185 } |
| 153 | 186 |
| 154 - (void)setTitle:(int)title { | |
| 155 NSMutableParagraphStyle* style = [[NSMutableParagraphStyle new] autorelease]; | |
| 156 style.lineSpacing = 6; | |
| 157 | |
| 158 title_.attributedStringValue = [[[NSAttributedString alloc] | |
| 159 initWithString:l10n_util::GetNSString(title) | |
| 160 attributes:@{NSParagraphStyleAttributeName : style}] autorelease]; | |
| 161 } | |
| 162 | |
| 163 - (void)setMessage:(int)message { | |
| 164 message_.stringValue = l10n_util::GetNSString(message); | |
| 165 } | |
| 166 | |
| 167 - (void)setButtonTitle:(int)buttonTitle { | |
| 168 button_.title = l10n_util::GetNSString(buttonTitle); | |
| 169 [button_ sizeToFit]; | |
| 170 } | |
| 171 | |
| 172 - (void)setHelpLinkTitle:(int)helpLinkTitle URL:(NSString*)url { | |
| 173 NSString* title = l10n_util::GetNSString(helpLinkTitle); | |
| 174 [help_ setMessage:title | |
| 175 withFont:message_.font | |
| 176 messageColor:message_.textColor]; | |
| 177 [help_ addLinkRange:NSMakeRange(0, title.length) | |
| 178 withURL:url | |
| 179 linkColor:message_.textColor]; | |
| 180 [help_ sizeToFit]; | |
| 181 } | |
| 182 | |
| 183 - (void)buttonClicked { | 187 - (void)buttonClicked { |
| 184 [delegate_ sadTabViewButtonClicked:self]; | 188 sadTab_->PerformAction(chrome::SadTab::Action::BUTTON); |
| 185 } | 189 } |
| 186 | 190 |
| 187 // Called when someone clicks on the embedded link. | 191 // Called when someone clicks on the embedded link. |
| 188 - (BOOL)textView:(NSTextView*)textView | 192 - (BOOL)textView:(NSTextView*)textView |
| 189 clickedOnLink:(id)link | 193 clickedOnLink:(id)link |
| 190 atIndex:(NSUInteger)charIndex { | 194 atIndex:(NSUInteger)charIndex { |
| 191 [delegate_ sadTabView:self helpLinkClickedWithURL:(NSString*)link]; | 195 sadTab_->PerformAction(chrome::SadTab::Action::HELP_LINK); |
| 192 return YES; | 196 return YES; |
| 193 } | 197 } |
| 194 | 198 |
| 199 - (NSRange)textView:(NSTextView*)textView |
| 200 willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange |
| 201 toCharacterRange:(NSRange)newSelectedCharRange { |
| 202 return NSMakeRange(0, 0); |
| 203 } |
| 204 |
| 195 @end | 205 @end |
| OLD | NEW |