manage_passwords_bubble_pending_view_controller.mm revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <algorithm> 6 7#import "chrome/browser/ui/cocoa/passwords/manage_passwords_bubble_pending_view_controller.h" 8 9#include "base/strings/sys_string_conversions.h" 10#import "chrome/browser/ui/cocoa/bubble_combobox.h" 11#import "chrome/browser/ui/cocoa/passwords/manage_password_item_view_controller.h" 12#include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h" 13#include "chrome/browser/ui/passwords/save_password_refusal_combobox_model.h" 14#include "chrome/grit/generated_resources.h" 15#import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h" 16#include "ui/base/l10n/l10n_util.h" 17#include "ui/base/models/combobox_model.h" 18 19using namespace password_manager::mac::ui; 20 21@interface ManagePasswordsBubblePendingViewController () 22- (void)onSaveClicked:(id)sender; 23- (void)onNopeClicked:(id)sender; 24- (void)onNeverForThisSiteClicked:(id)sender; 25@end 26 27@implementation ManagePasswordsBubblePendingViewController 28 29- (id)initWithModel:(ManagePasswordsBubbleModel*)model 30 delegate:(id<ManagePasswordsBubblePendingViewDelegate>)delegate { 31 if ((self = [super initWithNibName:nil bundle:nil])) { 32 model_ = model; 33 delegate_ = delegate; 34 } 35 return self; 36} 37 38- (void)bubbleWillDisappear { 39 // The "nope" drop-down won't be dismissed until the user chooses an option, 40 // but if the bubble is dismissed (by cross-platform code) before the user 41 // makes a choice, then the choice won't actually take any effect. 42 [[nopeButton_ menu] cancelTrackingWithoutAnimation]; 43} 44 45- (void)onSaveClicked:(id)sender { 46 model_->OnSaveClicked(); 47 [delegate_ viewShouldDismiss]; 48} 49 50- (void)onNopeClicked:(id)sender { 51 model_->OnNopeClicked(); 52 [delegate_ viewShouldDismiss]; 53} 54 55- (void)onNeverForThisSiteClicked:(id)sender { 56 if (model_->best_matches().empty()) { 57 // Skip confirmation if there are no existing passwords for this site. 58 model_->OnNeverForThisSiteClicked(); 59 [delegate_ viewShouldDismiss]; 60 } else { 61 [delegate_ passwordShouldNeverBeSavedOnSiteWithExistingPasswords]; 62 } 63} 64 65- (void)loadView { 66 self.view = [[[NSView alloc] initWithFrame:NSZeroRect] autorelease]; 67 68 // ----------------------------------- 69 // | Title | 70 // | ----------------------------- | (1 px border) 71 // | username password | 72 // | ----------------------------- | (1 px border) 73 // | [Save] [Nope v] | 74 // ----------------------------------- 75 76 // The bubble should be wide enough to fit the title row, the username and 77 // password row, and the buttons row on one line each, but not smaller than 78 // kDesiredBubbleWidth. 79 80 // Create the elements and add them to the view. 81 82 // Title. 83 NSTextField* titleLabel = 84 [self addTitleLabel:base::SysUTF16ToNSString(model_->title())]; 85 86 // Password item. 87 // It should be at least as wide as the box without the padding. 88 passwordItem_.reset([[ManagePasswordItemViewController alloc] 89 initWithModel:model_ 90 passwordForm:model_->pending_credentials() 91 position:password_manager::ui::FIRST_ITEM]); 92 NSView* password = [passwordItem_ view]; 93 [self.view addSubview:password]; 94 95 // Save button. 96 saveButton_.reset( 97 [[self addButton:l10n_util::GetNSString(IDS_PASSWORD_MANAGER_SAVE_BUTTON) 98 target:self 99 action:@selector(onSaveClicked:)] retain]); 100 101 // Nope combobox. 102 SavePasswordRefusalComboboxModel comboboxModel; 103 nopeButton_.reset([[BubbleCombobox alloc] initWithFrame:NSZeroRect 104 pullsDown:YES 105 model:&comboboxModel]); 106 NSMenuItem* nopeItem = 107 [nopeButton_ itemAtIndex:SavePasswordRefusalComboboxModel::INDEX_NOPE]; 108 [nopeItem setTarget:self]; 109 [nopeItem setAction:@selector(onNopeClicked:)]; 110 NSMenuItem* neverItem = [nopeButton_ 111 itemAtIndex:SavePasswordRefusalComboboxModel::INDEX_NEVER_FOR_THIS_SITE]; 112 [neverItem setTarget:self]; 113 [neverItem setAction:@selector(onNeverForThisSiteClicked:)]; 114 115 // Insert a dummy row at the top and set its title to the desired title. 116 // Must be done in two steps to prevent NSPopUpButton from removing 117 // duplicates. 118 [nopeButton_ insertItemWithTitle:@"" atIndex:0]; 119 [[nopeButton_ itemAtIndex:0] 120 setTitle:l10n_util::GetNSString(IDS_PASSWORD_MANAGER_CANCEL_BUTTON)]; 121 122 [nopeButton_ sizeToFit]; 123 [self.view addSubview:nopeButton_.get()]; 124 125 // Compute the bubble width using the password item. 126 const CGFloat contentWidth = 127 kFramePadding + NSWidth([password frame]) + kFramePadding; 128 const CGFloat width = std::max(kDesiredBubbleWidth, contentWidth); 129 130 // Layout the elements, starting at the bottom and moving up. 131 132 // Buttons go on the bottom row and are right-aligned. 133 // Start with [Save]. 134 CGFloat curX = width - kFramePadding - NSWidth([saveButton_ frame]); 135 CGFloat curY = kFramePadding; 136 [saveButton_ setFrameOrigin:NSMakePoint(curX, curY)]; 137 138 // [Save] goes to the left of [Nope]. 139 curX -= kRelatedControlHorizontalPadding + NSWidth([nopeButton_ frame]); 140 curY = kFramePadding + 141 (NSHeight([saveButton_ frame]) - NSHeight([nopeButton_ frame])) / 2.0; 142 [nopeButton_ setFrameOrigin:NSMakePoint(curX, curY)]; 143 144 // Password item goes on the next row and is shifted right. 145 curX = kFramePadding; 146 curY = NSMaxY([saveButton_ frame]) + kUnrelatedControlVerticalPadding; 147 [password setFrameOrigin:NSMakePoint(curX, curY)]; 148 149 // Title goes at the top after some padding. 150 curY = NSMaxY([password frame]) + kUnrelatedControlVerticalPadding; 151 [titleLabel setFrameOrigin:NSMakePoint(curX, curY)]; 152 153 // Update the bubble size. 154 const CGFloat height = NSMaxY([titleLabel frame]) + kFramePadding; 155 [self.view setFrame:NSMakeRect(0, 0, width, height)]; 156} 157 158@end 159 160@implementation ManagePasswordsBubblePendingViewController (Testing) 161 162- (NSButton*)saveButton { 163 return saveButton_.get(); 164} 165 166- (BubbleCombobox*)nopeButton { 167 return nopeButton_.get(); 168} 169 170@end 171