Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(976)

Unified Diff: chrome/browser/ui/cocoa/browser/password_generation_bubble_controller.mm

Issue 11416047: Add mac UI for password generation (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add some comments. Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/cocoa/browser/password_generation_bubble_controller.mm
diff --git a/chrome/browser/ui/cocoa/browser/password_generation_bubble_controller.mm b/chrome/browser/ui/cocoa/browser/password_generation_bubble_controller.mm
new file mode 100644
index 0000000000000000000000000000000000000000..b881de59bc667eefc4496addd82d6138c96b1509
--- /dev/null
+++ b/chrome/browser/ui/cocoa/browser/password_generation_bubble_controller.mm
@@ -0,0 +1,295 @@
+// Copyright (c) 2012 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 <cmath>
+
+#import "chrome/browser/ui/cocoa/browser/password_generation_bubble_controller.h"
+
+#include "base/sys_string_conversions.h"
+#include "chrome/common/autofill_messages.h"
+#include "chrome/browser/autofill/password_generator.h"
+#include "chrome/browser/password_manager/password_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#import "chrome/browser/ui/cocoa/info_bubble_view.h"
+#import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
+#import "chrome/browser/ui/cocoa/tracking_area.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/common/password_form.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
Scott Hess - ex-Googler 2012/11/17 01:22:41 Line of whitespace before each comment and between
Garrett Casto 2012/11/19 22:17:42 Done.
Garrett Casto 2012/11/19 22:17:42 Done.
+// We make the icon smaller by this decrease some of the whitespace.
+const int kIconWidthInset = 3;
+// This helps center the image to deal with the fact that there is a border
+// on the right side of the textfield.
+const int kIconOffset = 2;
+} // namespace
+
+// Customized StyledTextFieldCell to display one button decoration that changes
+// on hover.
+@interface PasswordGenerationTextFieldCell : StyledTextFieldCell {
+ @private
+ PasswordGenerationBubbleController* controller_;
+ BOOL hovering_;
+ scoped_nsobject<NSImage> normalImage_;
+ scoped_nsobject<NSImage> hoverImage_;
+}
+
+- (void)setUpWithController:(PasswordGenerationBubbleController*)controller
+ normalImage:(NSImage*)normalImage
+ hoverImage:(NSImage*)hoverImage;
+- (void)mouseEntered:(NSEvent*)theEvent
+ inView:(PasswordGenerationTextField*)controlView;
+- (void)mouseExited:(NSEvent*)theEvent
+ inView:(PasswordGenerationTextField*)controlView;
+- (BOOL)mouseDown:(NSEvent*)theEvent
+ inView:(PasswordGenerationTextField*)controlView;
+- (void)setUpTrackingAreaInRect:(NSRect)frame
+ ofView:(PasswordGenerationTextField*)controlView;
+@end
+
+@implementation PasswordGenerationTextField
+
++ (Class)cellClass {
+ return [PasswordGenerationTextFieldCell class];
+}
+
+- (id)initWithFrame:(NSRect)frame
+ withController:(PasswordGenerationBubbleController*)controller
+ normalImage:(NSImage*)normalImage
+ hoverImage:(NSImage*)hoverImage {
+ self = [super initWithFrame:frame];
+ if (self) {
+ DCHECK([[self cell] isKindOfClass:[PasswordGenerationTextFieldCell class]]);
+ [[self cell] setUpWithController:controller
+ normalImage:normalImage
+ hoverImage:hoverImage];
+ [[self cell] setLineBreakMode:NSLineBreakByTruncatingTail];
+ [[self cell] setTruncatesLastVisibleLine:YES];
Scott Hess - ex-Googler 2012/11/17 01:22:41 These two look like attributes of the cell, not dy
Garrett Casto 2012/11/19 22:17:42 AutocompleteTextField does this in awakeFromNib, b
Scott Hess - ex-Googler 2012/11/19 23:20:35 Generally the rule is that less-specific init meth
Garrett Casto 2012/11/27 07:59:49 Done.
+ [[self cell] setUpTrackingAreaInRect:[self bounds] ofView:self];
Scott Hess - ex-Googler 2012/11/17 01:22:41 In Objective-C, all of the [self cell] are dynamic
Garrett Casto 2012/11/19 22:17:42 I didn't notice anything obvious in base/mac/... I
Scott Hess - ex-Googler 2012/11/19 23:20:35 Basically like: - (PGTFC*)cell { return base::m
Garrett Casto 2012/11/27 07:59:49 Done, though as someone new to objective C, can yo
sail 2012/11/28 06:47:16 The reason there isn't strict type checking here i
+ }
+ return self;
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent {
+ [[self cell] mouseEntered:theEvent inView:self];
+}
+
+- (void)mouseExited:(NSEvent*)theEvent {
+ [[self cell] mouseExited:theEvent inView:self];
+}
+
+- (void)mouseDown:(NSEvent*)theEvent {
+ // Let the cell handle the click if it's in the decoration.
+ if (![[self cell] mouseDown:theEvent inView:self]) {
+ [[self currentEditor] mouseDown:theEvent];
+ }
+}
+
+@end
+
+@implementation PasswordGenerationTextFieldCell
+
+- (void)setUpWithController:(PasswordGenerationBubbleController*)controller
+ normalImage:(NSImage*)normalImage
+ hoverImage:(NSImage*)hoverImage {
+ controller_ = controller;
+ hovering_ = NO;
+ normalImage_.reset([normalImage retain]);
+ hoverImage_.reset([hoverImage retain]);
+}
+
+- (NSRect)getFrameForIcon:(NSRect*)cellFrame {
Scott Hess - ex-Googler 2012/11/17 01:22:41 In all but one case, you use either the return val
Garrett Casto 2012/11/19 22:17:42 Done.
+ NSRect iconFrame;
+ NSDivideRect(*cellFrame, &iconFrame, cellFrame,
+ [normalImage_ size].width - kIconWidthInset, NSMaxXEdge);
Scott Hess - ex-Googler 2012/11/17 01:22:41 I'm not entirely following how you're using this.
Garrett Casto 2012/11/19 22:17:42 I'm using the same icon on both Windows and Mac (a
Scott Hess - ex-Googler 2012/11/19 23:20:35 Still not sure I understand where you're going, he
Garrett Casto 2012/11/27 07:59:49 I changed this to just crop the image, which hopef
Scott Hess - ex-Googler 2012/11/28 20:01:05 Sounds like it should.
+ return iconFrame;
+}
+
+- (BOOL)eventIsInDecoration:(NSEvent*)theEvent
+ inView:(PasswordGenerationTextField*)controlView {
+ NSPoint mouseLocation = [controlView convertPoint:[theEvent locationInWindow]
+ fromView:nil];
+ NSRect cellFrame = [controlView bounds];
+ return NSMouseInRect(mouseLocation,
+ [self getFrameForIcon:&cellFrame],
+ [controlView isFlipped]);
+}
+
+- (void)mouseEntered:(NSEvent*)theEvent
+ inView:(PasswordGenerationTextField*)controlView {
+ hovering_ = YES;
+ [controlView setNeedsDisplay:YES];
+}
+
+- (void)mouseExited:(NSEvent*)theEvent
+ inView:(PasswordGenerationTextField*)controlView {
+ hovering_ = NO;
+ [controlView setNeedsDisplay:YES];
+}
+
+- (BOOL)mouseDown:(NSEvent*)theEvent
+ inView:(PasswordGenerationTextField*)controlView {
+ if ([self eventIsInDecoration:theEvent
+ inView:controlView]) {
Scott Hess - ex-Googler 2012/11/17 01:22:41 This shouldn't need to wrap.
Garrett Casto 2012/11/19 22:17:42 Done.
+ [controller_ regeneratePassword];
+ return YES;
+ }
+ return NO;
+}
+
+- (NSImage*)getImage {
+ if (hovering_)
+ return hoverImage_;
+ return normalImage_;
+}
+
+- (NSRect)adjustFrameForFrame:(NSRect)frame {
+ // By default, there appears to be a 2 pixel gap between what is considered
+ // part of the textFrame and what is considered part of the icon. I'm guessing
+ // it has to do with inclusivity of the end points.
+ return NSMakeRect(NSMinX(frame),
+ NSMinY(frame),
+ NSWidth(frame) + 2,
+ NSHeight(frame));
Scott Hess - ex-Googler 2012/11/17 01:22:41 This seems sketchy. Is there something drawing in
Garrett Casto 2012/11/19 22:17:42 Looking at this some more, it looks like this migh
Scott Hess - ex-Googler 2012/11/28 20:01:05 I'm not sure I see the issue you mention clicking
+}
+
+- (NSRect)textFrameForFrame:(NSRect)cellFrame {
+ // Baseclass insets the rect by baselineAdjust.
+ NSRect textFrame = [super textFrameForFrame:cellFrame];
+ [self getFrameForIcon:&textFrame];
+ return [self adjustFrameForFrame:textFrame];
+}
+
+- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
+ [self getFrameForIcon:&cellFrame];
+ return [self adjustFrameForFrame:cellFrame];
+}
+
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
+ NSImage* image = [self getImage];
+ NSRect iconFrame = [self getFrameForIcon:&cellFrame];
+ // Center the image in the available space
+ const CGFloat x_inset =
+ std::floor((NSWidth(iconFrame) - [image size].width) / 2.0);
+ const CGFloat y_inset =
+ std::floor((NSHeight(iconFrame) - [image size].height) / 2.0);
+ NSRect centeredFrame = NSInsetRect(iconFrame, x_inset, y_inset);
Scott Hess - ex-Googler 2012/11/17 01:22:41 This all might be cleaner using NSMidX(), NSMidY()
Garrett Casto 2012/11/19 22:17:42 Personally I find the current implementation sligh
Scott Hess - ex-Googler 2012/11/19 23:20:35 NSImage can draw at a point, instead of in a rect.
+
+ // Shift the image over to help even out the white space on both sides (since
+ // there is a border taking up some space on the right).
+ [image drawInRect:NSOffsetRect(centeredFrame, -kIconOffset, 0)
+ fromRect:NSZeroRect // Entire image
+ operation:NSCompositeSourceOver
+ fraction:1.0
+ respectFlipped:YES
+ hints:nil];
+
+ [super drawInteriorWithFrame:cellFrame inView:controlView];
+}
+
+-(void) setUpTrackingAreaInRect:(NSRect)frame
Scott Hess - ex-Googler 2012/11/17 01:22:41 space before (void), not after.
Garrett Casto 2012/11/19 22:17:42 Done.
+ ofView:(PasswordGenerationTextField*)view {
+ NSRect iconFrame = [self getFrameForIcon:&frame];
+ scoped_nsobject<CrTrackingArea> area(
+ [[CrTrackingArea alloc] initWithRect:iconFrame
+ options:NSTrackingMouseEnteredAndExited |
+ NSTrackingActiveAlways
+ owner:view
+ userInfo:nil]);
+ [view addTrackingArea:area];
+}
+
+- (CGFloat)baselineAdjust {
+ return 1.0;
+}
+
+- (CGFloat)cornerRadius {
+ return 4.0;
+}
+
+- (BOOL)shouldDrawBezel {
+ return YES;
+}
+
+@end
+
+@implementation PasswordGenerationBubbleController
+
+- (id)initWithBrowser:(Browser*)parentBrowser
+ anchoredAt:(NSPoint)point
+ renderViewHost:(content::RenderViewHost*)renderViewHost
+ passwordManager:(PasswordManager*)passwordManager
+ usingGenerator:(autofill::PasswordGenerator*)passwordGenerator
+ forForm:(const content::PasswordForm&)form {
+ NSRect contentRect = NSMakeRect(0, 0, 260, 71);
Scott Hess - ex-Googler 2012/11/17 01:22:41 That seems pretty unlikely to me.
Garrett Casto 2012/11/19 22:17:42 ? An issue with hard coding number?
Scott Hess - ex-Googler 2012/11/19 23:20:35 Yeah. I have no idea what it means. I can see wh
+ scoped_nsobject<InfoBubbleWindow> window(
+ [[InfoBubbleWindow alloc] initWithContentRect:contentRect
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+ if (self = [super initWithWindow:window
+ parentWindow:parentBrowser->window()->GetNativeWindow()
+ anchoredAt:point]) {
+ passwordGenerator_ = passwordGenerator;
+ renderViewHost_ = renderViewHost;
+ passwordManager_ = passwordManager;
+ form_ = form;
+ [[self bubble] setArrowLocation:info_bubble::kTopLeft];
+ }
+
+ [self performLayout];
Scott Hess - ex-Googler 2012/11/17 01:22:41 Should be in the if() clause.
Garrett Casto 2012/11/19 22:17:42 Done.
+ return self;
+}
+
+- (void)performLayout {
+ NSView* contentView = [[self window] contentView];
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+ textField_ =
+ [[PasswordGenerationTextField alloc]
+ initWithFrame:NSMakeRect(9, 9, 172, 23)
+ withController:self
+ normalImage:rb.GetNativeImageNamed(IDR_RELOAD_DIMMED).ToNSImage()
+ hoverImage:rb.GetNativeImageNamed(IDR_RELOAD).ToNSImage()];
+ [textField_ setFont:[NSFont boldSystemFontOfSize:11]];
Scott Hess - ex-Googler 2012/11/17 01:22:41 This seems like it should be using some sort of gf
Garrett Casto 2012/11/19 22:17:42 Done.
+ [textField_
+ setStringValue:base::SysUTF8ToNSString(passwordGenerator_->Generate())];
+ [contentView addSubview:textField_];
Scott Hess - ex-Googler 2012/11/19 23:20:35 Is this field still editable? If so, do you want
Garrett Casto 2012/11/27 07:59:49 I think that I like this better than hooking up th
Scott Hess - ex-Googler 2012/11/28 20:01:05 nack, that's not what I meant. I meant: [textFie
+
+ NSButton* button = [[NSButton alloc]
+ initWithFrame:NSMakeRect(181, 6, 76, 25)];
+ [button setBezelStyle:NSRoundedBezelStyle];
+ [button setTitle:@"Try it"];
+ [button setTarget:self];
+ [button setAction:@selector(fillPassword:)];
+ [contentView addSubview:button];
+
+ NSTextField* title = [[NSTextField alloc]
+ initWithFrame:NSMakeRect(8, 42, 138, 17)];
+ [title setEditable:NO];
+ [title setBordered:NO];
+ [title setStringValue:@"Password Suggestion"];
+ [contentView addSubview:title];
+}
Scott Hess - ex-Googler 2012/11/17 01:22:41 Sorry, but all of this hard-coded positioning is j
Garrett Casto 2012/11/19 22:17:42 So what's the right way of doing this then? I want
Scott Hess - ex-Googler 2012/11/19 23:20:35 At minimum, you could be laying things out relativ
Garrett Casto 2012/11/27 07:59:49 Done. I guess the issue I was having is that there
Scott Hess - ex-Googler 2012/11/28 20:01:05 You can punt on the actual localization, but unles
Scott Hess - ex-Googler 2012/11/28 20:01:05 Oh, it's worse than that - when you hard-code the
+
+- (IBAction)fillPassword:(id)sender {
+ renderViewHost_->Send(
+ new AutofillMsg_GeneratedPasswordAccepted(
+ renderViewHost_->GetRoutingID(),
+ base::SysNSStringToUTF16([textField_ stringValue])));
+ passwordManager_->SetFormHasGeneratedPassword(form_);
+ [self close];
+}
+
+- (void)regeneratePassword {
+ [textField_
+ setStringValue:base::SysUTF8ToNSString(passwordGenerator_->Generate())];
+}
+
+@end

Powered by Google App Engine
This is Rietveld 408576698