1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
|
// Copyright 2013 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.
#include "chrome/browser/ui/cocoa/autofill/generated_credit_card_bubble_cocoa.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
#include "chrome/browser/ui/autofill/generated_credit_card_bubble_controller.h"
#include "chrome/browser/ui/autofill/generated_credit_card_bubble_view.h"
#import "chrome/browser/ui/cocoa/base_bubble_controller.h"
#import "chrome/browser/ui/cocoa/info_bubble_view.h"
#import "chrome/browser/ui/cocoa/info_bubble_window.h"
#include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
#include "skia/ext/skia_utils_mac.h"
#import "ui/base/cocoa/controls/hyperlink_text_view.h"
#include "ui/base/cocoa/window_size_constants.h"
#include "ui/native_theme/native_theme.h"
using autofill::GeneratedCreditCardBubbleCocoa;
namespace {
const CGFloat kTitlePadding = 20.0;
const CGFloat kInset = 20.0;
} // namespace
// The Cocoa side of the bubble controller.
@interface GeneratedCreditCardBubbleControllerCocoa :
BaseBubbleController<NSTextViewDelegate> {
// Bridge to C++ side.
scoped_ptr<GeneratedCreditCardBubbleCocoa> bridge_;
}
- (id)initWithParentWindow:(NSWindow*)parentWindow
bridge:(GeneratedCreditCardBubbleCocoa*)bridge;
// Show the bubble at the given |anchor| point. Coordinates are in screen space.
- (void)showAtAnchor:(NSPoint)anchor;
// Return true if the bubble is in the process of hiding.
- (BOOL)isHiding;
// Build the window contents and lay them out.
- (void)performLayoutWithController:
(autofill::GeneratedCreditCardBubbleController*)controller;
@end
@implementation GeneratedCreditCardBubbleControllerCocoa
- (id)initWithParentWindow:(NSWindow*)parentWindow
bridge:(GeneratedCreditCardBubbleCocoa*)bridge {
DCHECK(bridge);
base::scoped_nsobject<InfoBubbleWindow> window(
[[InfoBubbleWindow alloc]
initWithContentRect:ui::kWindowSizeDeterminedLater
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO]);
if ((self = [super initWithWindow:window
parentWindow:parentWindow
anchoredAt:NSZeroPoint])) {
[window setCanBecomeKeyWindow:NO];
bridge_.reset(bridge);
ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
[[self bubble] setAlignment:info_bubble::kAlignArrowToAnchor];
[[self bubble] setArrowLocation:info_bubble::kTopRight];
[[self bubble] setBackgroundColor:
gfx::SkColorToCalibratedNSColor(nativeTheme->GetSystemColor(
ui::NativeTheme::kColorId_DialogBackground))];
[self performLayoutWithController:bridge->controller().get()];
}
return self;
}
- (void)windowWillClose:(NSNotification*)notification {
bridge_->OnBubbleClosing();
[super windowWillClose:notification];
}
// Called when embedded links are clicked.
- (BOOL)textView:(NSTextView*)textView
clickedOnLink:(id)link
atIndex:(NSUInteger)charIndex {
bridge_->OnLinkClicked();
return YES;
}
- (void)showAtAnchor:(NSPoint)anchorPoint {
[self setAnchorPoint:anchorPoint];
[self showWindow:nil];
}
- (BOOL)isHiding {
InfoBubbleWindow* window =
base::mac::ObjCCastStrict<InfoBubbleWindow>([self window]);
return [window isClosing];
}
- (void)performLayoutWithController:
(autofill::GeneratedCreditCardBubbleController*)controller {
CGFloat bubbleWidth = autofill::GeneratedCreditCardBubbleView::kContentsWidth;
// Build the bubble title.
NSFont* titleFont = [NSFont systemFontOfSize:15.0];
NSString* title = base::SysUTF16ToNSString(controller->TitleText());
base::scoped_nsobject<NSTextField> titleView(
[[NSTextField alloc] initWithFrame:NSZeroRect]);
[titleView setDrawsBackground:NO];
[titleView setBezeled:NO];
[titleView setEditable:NO];
[titleView setSelectable:NO];
[titleView setStringValue:title];
[titleView setFont:titleFont];
[titleView sizeToFit];
bubbleWidth = std::max(bubbleWidth, NSWidth([titleView frame]) + 2 * kInset);
// Build the contents view.
base::scoped_nsobject<HyperlinkTextView> contentsView(
[[HyperlinkTextView alloc] initWithFrame:NSZeroRect]);
[contentsView setEditable:NO];
[contentsView setDelegate:self];
NSFont* font = [NSFont systemFontOfSize:[NSFont systemFontSize]];
NSFont* boldFont = [NSFont boldSystemFontOfSize:[NSFont systemFontSize]];
[contentsView setMessage:base::SysUTF16ToNSString(controller->ContentsText())
withFont:font
messageColor:[NSColor blackColor]];
const std::vector<autofill::TextRange>& text_ranges =
controller->ContentsTextRanges();
for (size_t i = 0; i < text_ranges.size(); ++i) {
NSRange range = text_ranges[i].range.ToNSRange();
if (text_ranges[i].is_link) {
[contentsView addLinkRange:range
withName:@(i)
linkColor:[NSColor blueColor]];
} else {
[[contentsView textStorage]
addAttributes:@{ NSFontAttributeName : boldFont }
range:range];
}
}
[contentsView setVerticallyResizable:YES];
[contentsView setFrameSize:NSMakeSize(bubbleWidth - 2 * kInset, CGFLOAT_MAX)];
[contentsView sizeToFit];
// Sizes are computed, now lay out the individual parts.
[contentsView setFrameOrigin:NSMakePoint(kInset, kInset)];
[titleView setFrameOrigin:
NSMakePoint(kInset, NSMaxY([contentsView frame]) + kTitlePadding)];
[[[self window] contentView] setSubviews:@[ contentsView, titleView ]];
// Update window frame.
NSRect windowFrame = [[self window] frame];
windowFrame.size =
NSMakeSize(bubbleWidth, NSMaxY([titleView frame]) + kInset);
[[self window] setFrame:windowFrame display:YES];
}
@end
namespace autofill {
// static
base::WeakPtr<GeneratedCreditCardBubbleView>
GeneratedCreditCardBubbleView::Create(
const base::WeakPtr<GeneratedCreditCardBubbleController>& controller) {
return (new GeneratedCreditCardBubbleCocoa(controller))->weak_ptr_factory_.
GetWeakPtr();
}
GeneratedCreditCardBubbleCocoa::GeneratedCreditCardBubbleCocoa(
const base::WeakPtr<GeneratedCreditCardBubbleController>& controller)
: bubbleController_(nil),
controller_(controller),
weak_ptr_factory_(this) {
}
GeneratedCreditCardBubbleCocoa::~GeneratedCreditCardBubbleCocoa() {}
void GeneratedCreditCardBubbleCocoa::Show() {
DCHECK(controller_.get());
NSView* browser_view =
controller_->web_contents()->GetNativeView();
NSWindow* parent_window = [browser_view window];
LocationBarViewMac* location_bar =
[[parent_window windowController] locationBarBridge];
// |location_bar| can be NULL during initialization stages.
if (!location_bar) {
// Technically, Show() should never be called during initialization.
NOTREACHED();
delete this;
return;
}
if (!bubbleController_) {
bubbleController_ = [[GeneratedCreditCardBubbleControllerCocoa alloc]
initWithParentWindow:parent_window
bridge:this];
}
// |bubbleController_| is supposed to take ownership of |this|. If it can't be
// constructed, clean up and abort showing.
if (!bubbleController_) {
delete this;
return;
}
NSPoint anchor = location_bar->GetGeneratedCreditCardBubblePoint();
[bubbleController_ showAtAnchor:[parent_window convertBaseToScreen:anchor]];
}
void GeneratedCreditCardBubbleCocoa::Hide() {
[bubbleController_ close];
}
bool GeneratedCreditCardBubbleCocoa::IsHiding() const {
return [bubbleController_ isHiding];
}
void GeneratedCreditCardBubbleCocoa::OnBubbleClosing() {
bubbleController_ = nil;
}
void GeneratedCreditCardBubbleCocoa::OnLinkClicked() {
if (controller_)
controller_->OnLinkClicked();
}
} // autofill
|