Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / passwords / manage_passwords_bubble_manage_view_controller.mm
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 #import "chrome/browser/ui/cocoa/passwords/manage_passwords_bubble_manage_view_controller.h"
6
7 #include <cmath>
8
9 #include "base/strings/sys_string_conversions.h"
10 #include "chrome/browser/ui/chrome_style.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 "grit/generated_resources.h"
14 #include "skia/ext/skia_utils_mac.h"
15 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
16 #import "ui/base/cocoa/controls/hyperlink_button_cell.h"
17 #include "ui/base/l10n/l10n_util.h"
18
19 using namespace password_manager::mac::ui;
20
21 @implementation PasswordItemListView
22 - (id)initWithModel:(ManagePasswordsBubbleModel*)model {
23   if ((self = [super initWithFrame:NSZeroRect])) {
24     base::scoped_nsobject<NSMutableArray> items([[NSMutableArray alloc] init]);
25
26     // Create and lay out the items.
27     const CGFloat curX = 0;
28     CGFloat maxX = 0;
29     CGFloat curY = 0;
30     for (autofill::ConstPasswordFormMap::const_reverse_iterator i =
31              model->best_matches().rbegin();
32          i != model->best_matches().rend();
33          ++i) {
34       autofill::PasswordForm form = *i->second;
35       password_manager::ui::PasswordItemPosition position =
36           (&(*i) == &(*model->best_matches().begin()))
37               ? password_manager::ui::FIRST_ITEM
38               : password_manager::ui::SUBSEQUENT_ITEM;
39       base::scoped_nsobject<ManagePasswordItemViewController> item(
40           [[ManagePasswordItemViewController alloc] initWithModel:model
41                                                      passwordForm:form
42                                                          position:position]);
43       [items addObject:item.get()];
44       NSView* itemView = [item view];
45       [self addSubview:itemView];
46
47       // The items stack up on each other.
48       [itemView setFrameOrigin:NSMakePoint(curX, curY)];
49       maxX = NSMaxX([itemView frame]);
50       curY = NSMaxY([itemView frame]);
51     }
52     [self setFrameSize:NSMakeSize(maxX, curY)];
53     itemViews_.reset(items.release());
54   }
55   return self;
56 }
57 @end
58
59 @implementation PasswordItemListView (Testing)
60 - (NSArray*)itemViews {
61   return itemViews_.get();
62 }
63 @end
64
65 @implementation NoPasswordsView
66 - (id)initWithWidth:(CGFloat)width {
67   if ((self = [super initWithFrame:NSZeroRect])) {
68     [self setEditable:NO];
69     [self setSelectable:NO];
70     [self setDrawsBackground:NO];
71     [self setBezeled:NO];
72     [self setStringValue:l10n_util::GetNSString(
73         IDS_MANAGE_PASSWORDS_NO_PASSWORDS)];
74     [self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
75     [[self cell] setWraps:YES];
76     [self setFrameSize:NSMakeSize(width, MAXFLOAT)];
77     [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:self];
78   }
79   return self;
80 }
81 @end
82
83 @interface ManagePasswordsBubbleManageViewController ()
84 - (void)onDoneClicked:(id)sender;
85 - (void)onManageClicked:(id)sender;
86 @end
87
88 @implementation ManagePasswordsBubbleManageViewController
89
90 - (id)initWithModel:(ManagePasswordsBubbleModel*)model
91            delegate:(id<ManagePasswordsBubbleContentViewDelegate>)delegate {
92   if ((self = [super initWithNibName:nil bundle:nil])) {
93     model_ = model;
94     delegate_ = delegate;
95   }
96   return self;
97 }
98
99 - (void)loadView {
100   self.view = [[[NSView alloc] initWithFrame:NSZeroRect] autorelease];
101
102   // -----------------------------------
103   // |  Title                          |
104   // |  -----------------------------  | (1 px border)
105   // |    username   password      x   |
106   // |  -----------------------------  | (1 px border)
107   // |    username   password      x   |
108   // |  -----------------------------  | (1 px border)
109   // |    username   password      x   |
110   // |  -----------------------------  | (1 px border)
111   // |  Manage                 [Done]  |
112   // -----------------------------------
113
114   // The bubble should be wide enough to fit the title row, the username and
115   // password rows, and the buttons row on one line each, but not smaller than
116   // kDesiredBubbleWidth.
117
118   // Create the elements and add them to the view.
119   NSTextField* titleLabel =
120       [self addTitleLabel:base::SysUTF16ToNSString(model_->title())];
121
122   // Content. If we have a list of passwords to store for the current site, we
123   // display them to the user for management. Otherwise, we show a "No passwords
124   // for this site" message.
125   if (model_->best_matches().empty()) {
126     const CGFloat noPasswordsWidth = std::max(
127         kDesiredBubbleWidth - 2 * kFramePadding, NSWidth([titleLabel frame]));
128     contentView_.reset(
129         [[NoPasswordsView alloc] initWithWidth:noPasswordsWidth]);
130   } else {
131     contentView_.reset(
132         [[PasswordItemListView alloc] initWithModel:model_]);
133   }
134   [self.view addSubview:contentView_];
135   DCHECK_GE(NSWidth([contentView_ frame]), NSWidth([titleLabel frame]));
136
137   // Done button.
138   doneButton_.reset([[self addButton:l10n_util::GetNSString(IDS_DONE)
139                               target:self
140                               action:@selector(onDoneClicked:)] retain]);
141
142   // Manage button.
143   manageButton_.reset([[NSButton alloc] initWithFrame:NSZeroRect]);
144   base::scoped_nsobject<HyperlinkButtonCell> cell([[HyperlinkButtonCell alloc]
145       initTextCell:base::SysUTF16ToNSString(model_->manage_link())]);
146   [cell setControlSize:NSSmallControlSize];
147   [cell setShouldUnderline:NO];
148   [cell setUnderlineOnHover:NO];
149   [cell setTextColor:gfx::SkColorToCalibratedNSColor(
150       chrome_style::GetLinkColor())];
151   [manageButton_ setCell:cell.get()];
152   [manageButton_ sizeToFit];
153   [manageButton_ setTarget:self];
154   [manageButton_ setAction:@selector(onManageClicked:)];
155   [self.view addSubview:manageButton_];
156
157   // Layout the elements, starting at the bottom and moving up.
158
159   // The Done button goes in the bottom-right corner.
160   const CGFloat width = 2 * kFramePadding + NSWidth([contentView_ frame]);
161   CGFloat curX = width - kFramePadding - NSWidth([doneButton_ frame]);
162   CGFloat curY = kFramePadding;
163   [doneButton_ setFrameOrigin:NSMakePoint(curX, curY)];
164
165   // The Manage button goes in the bottom-left corner, centered vertically with
166   // the Done button.
167   curX = kFramePadding;
168   const CGFloat diffY = std::ceil(
169       (NSHeight([doneButton_ frame]) - NSHeight([manageButton_ frame])) / 2.0);
170   [manageButton_ setFrameOrigin:NSMakePoint(curX, curY + diffY)];
171
172   // The content goes above the button row.
173   curX = kFramePadding;
174   curY = NSMaxY([doneButton_ frame]) + kUnrelatedControlVerticalPadding;
175   [contentView_ setFrameOrigin:NSMakePoint(curX, curY)];
176
177   // The title goes above the content.
178   curY = NSMaxY([contentView_ frame]) + kUnrelatedControlVerticalPadding;
179   [titleLabel setFrameOrigin:NSMakePoint(curX, curY)];
180
181   curX = NSMaxX([contentView_ frame]) + kFramePadding;
182   curY = NSMaxY([titleLabel frame]) + kFramePadding;
183   DCHECK_EQ(width, curX);
184   [self.view setFrameSize:NSMakeSize(curX, curY)];
185 }
186
187 - (void)onDoneClicked:(id)sender {
188   model_->OnDoneClicked();
189   [delegate_ viewShouldDismiss];
190 }
191
192 - (void)onManageClicked:(id)sender {
193   model_->OnManageLinkClicked();
194   [delegate_ viewShouldDismiss];
195 }
196
197 @end
198
199 @implementation ManagePasswordsBubbleManageViewController (Testing)
200
201 - (NSButton*)doneButton {
202   return doneButton_.get();
203 }
204
205 - (NSButton*)manageButton {
206   return manageButton_.get();
207 }
208
209 - (NSView*)contentView {
210   return contentView_.get();
211 }
212
213 @end