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