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

Side by Side Diff: chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm

Issue 73293002: [rAC, OSX] Cleanup: Separate out WindowController (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Merge to HEAD Created 7 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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/autofill/autofill_dialog_cocoa.h" 5 #include "chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/mac/bundle_locations.h"
9 #include "base/mac/foundation_util.h"
10 #include "base/mac/scoped_nsobject.h" 8 #include "base/mac/scoped_nsobject.h"
11 #include "base/message_loop/message_loop.h" 9 #include "base/message_loop/message_loop.h"
12 #include "base/strings/sys_string_conversions.h" 10 #include "base/strings/sys_string_conversions.h"
13 #include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h" 11 #include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h"
14 #include "chrome/browser/ui/chrome_style.h"
15 #import "chrome/browser/ui/cocoa/autofill/autofill_account_chooser.h"
16 #import "chrome/browser/ui/cocoa/autofill/autofill_details_container.h" 12 #import "chrome/browser/ui/cocoa/autofill/autofill_details_container.h"
17 #include "chrome/browser/ui/cocoa/autofill/autofill_dialog_constants.h" 13 #import "chrome/browser/ui/cocoa/autofill/autofill_dialog_window_controller.h"
18 #import "chrome/browser/ui/cocoa/autofill/autofill_input_field.h"
19 #import "chrome/browser/ui/cocoa/autofill/autofill_loading_shield_controller.h"
20 #import "chrome/browser/ui/cocoa/autofill/autofill_main_container.h"
21 #import "chrome/browser/ui/cocoa/autofill/autofill_overlay_controller.h"
22 #import "chrome/browser/ui/cocoa/autofill/autofill_section_container.h"
23 #import "chrome/browser/ui/cocoa/autofill/autofill_sign_in_container.h"
24 #import "chrome/browser/ui/cocoa/autofill/autofill_textfield.h"
25 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sh eet.h" 14 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sh eet.h"
26 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_wi ndow.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_contents_view.h"
29 #include "grit/generated_resources.h"
30 #import "ui/base/cocoa/flipped_view.h"
31 #include "ui/base/cocoa/window_size_constants.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/gfx/platform_font.h"
34
35 const CGFloat kAccountChooserHeight = 20.0;
36 const CGFloat kMinimumContentsHeight = 101;
37
38 // Height of all decorations & paddings on main dialog together.
39 const CGFloat kDecorationHeight = kAccountChooserHeight +
40 autofill::kDetailVerticalPadding +
41 chrome_style::kClientBottomPadding +
42 chrome_style::kTitleTopPadding;
43 15
44 namespace autofill { 16 namespace autofill {
45 17
46 // static 18 // static
47 AutofillDialogView* AutofillDialogView::Create( 19 AutofillDialogView* AutofillDialogView::Create(
48 AutofillDialogViewDelegate* delegate) { 20 AutofillDialogViewDelegate* delegate) {
49 return new AutofillDialogCocoa(delegate); 21 return new AutofillDialogCocoa(delegate);
50 } 22 }
51 23
52 AutofillDialogCocoa::AutofillDialogCocoa(AutofillDialogViewDelegate* delegate) 24 AutofillDialogCocoa::AutofillDialogCocoa(AutofillDialogViewDelegate* delegate)
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 gfx::Size AutofillDialogCocoa::GetSize() const { 187 gfx::Size AutofillDialogCocoa::GetSize() const {
216 return gfx::Size(NSSizeToCGSize([[sheet_delegate_ window] frame].size)); 188 return gfx::Size(NSSizeToCGSize([[sheet_delegate_ window] frame].size));
217 } 189 }
218 190
219 content::WebContents* AutofillDialogCocoa::GetSignInWebContents() { 191 content::WebContents* AutofillDialogCocoa::GetSignInWebContents() {
220 return [sheet_delegate_ getSignInWebContents]; 192 return [sheet_delegate_ getSignInWebContents];
221 } 193 }
222 194
223 195
224 bool AutofillDialogCocoa::IsShowingOverlay() const { 196 bool AutofillDialogCocoa::IsShowingOverlay() const {
225 return [sheet_delegate_ IsShowingOverlay]; 197 return [sheet_delegate_ isShowingOverlay];
226 } 198 }
227 199
228 void AutofillDialogCocoa::OnConstrainedWindowClosed( 200 void AutofillDialogCocoa::OnConstrainedWindowClosed(
229 ConstrainedWindowMac* window) { 201 ConstrainedWindowMac* window) {
230 constrained_window_.reset(); 202 constrained_window_.reset();
231 // |this| belongs to |delegate_|, so no self-destruction here. 203 // |this| belongs to |delegate_|, so no self-destruction here.
232 delegate_->ViewClosed(); 204 delegate_->ViewClosed();
233 } 205 }
234 206
235 } // autofill 207 } // autofill
236
237 #pragma mark Field Editor
238
239 @interface AutofillDialogFieldEditor : NSTextView
240 @end
241
242
243 @implementation AutofillDialogFieldEditor
244
245 - (void)mouseDown:(NSEvent*)event {
246 // Delegate _must_ be notified before mouseDown is complete, since it needs
247 // to distinguish between mouseDown for already focused fields, and fields
248 // that will receive focus as part of the mouseDown.
249 AutofillTextField* textfield =
250 base::mac::ObjCCastStrict<AutofillTextField>([self delegate]);
251 [textfield onEditorMouseDown:self];
252 [super mouseDown:event];
253 }
254
255 @end
256
257
258 #pragma mark Window Controller
259
260 @interface AutofillDialogWindowController ()
261
262 // Compute maximum allowed height for the dialog.
263 - (CGFloat)maxHeight;
264
265 // Update size constraints on sign-in container.
266 - (void)updateSignInSizeConstraints;
267
268 // Notification that the WebContent's view frame has changed.
269 - (void)onContentViewFrameDidChange:(NSNotification*)notification;
270
271 @end
272
273
274 @implementation AutofillDialogWindowController (NSWindowDelegate)
275
276 - (id)windowWillReturnFieldEditor:(NSWindow*)window toObject:(id)client {
277 AutofillTextField* textfield = base::mac::ObjCCast<AutofillTextField>(client);
278 if (!textfield)
279 return nil;
280
281 if (!fieldEditor_) {
282 fieldEditor_.reset([[AutofillDialogFieldEditor alloc] init]);
283 [fieldEditor_ setFieldEditor:YES];
284 }
285 return fieldEditor_.get();
286 }
287
288 @end
289
290
291 @implementation AutofillDialogWindowController
292
293 - (id)initWithWebContents:(content::WebContents*)webContents
294 autofillDialog:(autofill::AutofillDialogCocoa*)autofillDialog {
295 DCHECK(webContents);
296
297 base::scoped_nsobject<ConstrainedWindowCustomWindow> window(
298 [[ConstrainedWindowCustomWindow alloc]
299 initWithContentRect:ui::kWindowSizeDeterminedLater]);
300
301 if ((self = [super initWithWindow:window])) {
302 [window setDelegate:self];
303 webContents_ = webContents;
304 autofillDialog_ = autofillDialog;
305
306 mainContainer_.reset([[AutofillMainContainer alloc]
307 initWithDelegate:autofillDialog->delegate()]);
308 [mainContainer_ setTarget:self];
309
310 signInContainer_.reset(
311 [[AutofillSignInContainer alloc] initWithDialog:autofillDialog]);
312 [[signInContainer_ view] setHidden:YES];
313
314 // Set dialog title.
315 titleTextField_.reset([[NSTextField alloc] initWithFrame:NSZeroRect]);
316 [titleTextField_ setEditable:NO];
317 [titleTextField_ setBordered:NO];
318 [titleTextField_ setDrawsBackground:NO];
319 [titleTextField_ setFont:[NSFont systemFontOfSize:15.0]];
320 [titleTextField_ setStringValue:
321 base::SysUTF16ToNSString(autofillDialog->delegate()->DialogTitle())];
322 [titleTextField_ sizeToFit];
323
324 accountChooser_.reset([[AutofillAccountChooser alloc]
325 initWithFrame:NSZeroRect
326 delegate:autofillDialog->delegate()]);
327
328 loadingShieldController_.reset(
329 [[AutofillLoadingShieldController alloc]
330 initWithDelegate:autofillDialog->delegate()]);
331 [[loadingShieldController_ view] setHidden:YES];
332
333 overlayController_.reset(
334 [[AutofillOverlayController alloc] initWithDelegate:
335 autofillDialog->delegate()]);
336 [[overlayController_ view] setHidden:YES];
337
338 // This needs a flipped content view because otherwise the size
339 // animation looks odd. However, replacing the contentView for constrained
340 // windows does not work - it does custom rendering.
341 base::scoped_nsobject<NSView> flippedContentView(
342 [[FlippedView alloc] initWithFrame:
343 [[[self window] contentView] frame]]);
344 [flippedContentView setSubviews:
345 @[accountChooser_,
346 titleTextField_,
347 [mainContainer_ view],
348 [signInContainer_ view],
349 [loadingShieldController_ view],
350 [overlayController_ view]]];
351 [flippedContentView setAutoresizingMask:
352 (NSViewWidthSizable | NSViewHeightSizable)];
353 [[[self window] contentView] addSubview:flippedContentView];
354 [mainContainer_ setAnchorView:[[accountChooser_ subviews] objectAtIndex:1]];
355 }
356 return self;
357 }
358
359 - (void)dealloc {
360 [[NSNotificationCenter defaultCenter] removeObserver:self];
361 [super dealloc];
362 }
363
364 - (CGFloat)maxHeight {
365 NSRect dialogFrameRect = [[self window] frame];
366 NSRect browserFrameRect =
367 [webContents_->GetView()->GetTopLevelNativeWindow() frame];
368 dialogFrameRect.size.height =
369 NSMaxY(dialogFrameRect) - NSMinY(browserFrameRect);
370 dialogFrameRect = [[self window] contentRectForFrameRect:dialogFrameRect];
371 return NSHeight(dialogFrameRect);
372 }
373
374 - (void)updateSignInSizeConstraints {
375 // Adjust for the size of all decorations and paddings outside main content.
376 CGFloat minHeight = kMinimumContentsHeight - kDecorationHeight;
377 CGFloat maxHeight = std::max([self maxHeight] - kDecorationHeight, minHeight);
378 CGFloat width = NSWidth([[[self window] contentView] frame]);
379
380 [signInContainer_ constrainSizeToMinimum:NSMakeSize(width, minHeight)
381 maximum:NSMakeSize(width, maxHeight)];
382 }
383
384 - (void)onContentViewFrameDidChange:(NSNotification*)notification {
385 [self updateSignInSizeConstraints];
386 if ([[signInContainer_ view] isHidden])
387 [self requestRelayout];
388 }
389
390 - (void)cancelRelayout {
391 [NSObject cancelPreviousPerformRequestsWithTarget:self
392 selector:@selector(performLayout)
393 object:nil];
394 }
395
396 - (void)requestRelayout {
397 [self cancelRelayout];
398 [self performSelector:@selector(performLayout) withObject:nil afterDelay:0.0];
399 }
400
401 - (NSSize)preferredSize {
402 NSSize size;
403
404 // Overall size is determined by either main container or sign in view.
405 if ([[signInContainer_ view] isHidden])
406 size = [mainContainer_ preferredSize];
407 else
408 size = [signInContainer_ preferredSize];
409
410 // Always make room for the header.
411 size.height += kDecorationHeight;
412
413 if (![[overlayController_ view] isHidden]) {
414 CGFloat height = [overlayController_ heightForWidth:size.width];
415 if (height != 0.0)
416 size.height = height;
417 }
418
419 // Show as much of the main view as is possible without going past the
420 // bottom of the browser window.
421 size.height = std::min(size.height, [self maxHeight]);
422
423 return size;
424 }
425
426 - (void)performLayout {
427 NSRect contentRect = NSZeroRect;
428 contentRect.size = [self preferredSize];
429 NSRect clientRect = contentRect;
430 clientRect.origin.y = chrome_style::kTitleTopPadding;
431 clientRect.size.height -= chrome_style::kTitleTopPadding +
432 chrome_style::kClientBottomPadding;
433
434 [titleTextField_ setStringValue:
435 base::SysUTF16ToNSString(autofillDialog_->delegate()->DialogTitle())];
436 [titleTextField_ sizeToFit];
437
438 NSRect headerRect, mainRect, titleRect, dummyRect;
439 NSDivideRect(clientRect, &headerRect, &mainRect,
440 kAccountChooserHeight, NSMinYEdge);
441 NSDivideRect(mainRect, &dummyRect, &mainRect,
442 autofill::kDetailVerticalPadding, NSMinYEdge);
443 headerRect = NSInsetRect(headerRect, chrome_style::kHorizontalPadding, 0);
444 NSDivideRect(headerRect, &titleRect, &headerRect,
445 NSWidth([titleTextField_ frame]), NSMinXEdge);
446
447 // Align baseline of title with bottom of accountChooser.
448 base::scoped_nsobject<NSLayoutManager> layout_manager(
449 [[NSLayoutManager alloc] init]);
450 NSFont* titleFont = [titleTextField_ font];
451 titleRect.origin.y += NSHeight(titleRect) -
452 [layout_manager defaultBaselineOffsetForFont:titleFont];
453 [titleTextField_ setFrame:titleRect];
454
455 [accountChooser_ setFrame:headerRect];
456 [accountChooser_ performLayout];
457 if ([[signInContainer_ view] isHidden]) {
458 [[mainContainer_ view] setFrame:mainRect];
459 [mainContainer_ performLayout];
460 } else {
461 [[signInContainer_ view] setFrame:mainRect];
462 }
463
464 [[loadingShieldController_ view] setFrame:contentRect];
465 [loadingShieldController_ performLayout];
466
467 [[overlayController_ view] setFrame:contentRect];
468 [overlayController_ performLayout];
469
470 NSRect frameRect = [[self window] frameRectForContentRect:contentRect];
471 [[self window] setFrame:frameRect display:YES];
472 [[self window] recalculateKeyViewLoop];
473 }
474
475 - (IBAction)accept:(id)sender {
476 if ([mainContainer_ validate])
477 autofillDialog_->delegate()->OnAccept();
478 else
479 [mainContainer_ makeFirstInvalidInputFirstResponder];
480 }
481
482 - (IBAction)cancel:(id)sender {
483 autofillDialog_->delegate()->OnCancel();
484 autofillDialog_->PerformClose();
485 }
486
487 - (void)show {
488 // Resizing the browser causes the ConstrainedWindow to move.
489 // Observe that to allow resizes based on browser size.
490 // NOTE: This MUST come last after all initial setup is done, because there
491 // is an immediate notification post registration.
492 DCHECK([self window]);
493 [[NSNotificationCenter defaultCenter]
494 addObserver:self
495 selector:@selector(onContentViewFrameDidChange:)
496 name:NSWindowDidMoveNotification
497 object:[self window]];
498
499 [self updateAccountChooser];
500 [self updateNotificationArea];
501 [self requestRelayout];
502 }
503
504 - (void)hide {
505 autofillDialog_->delegate()->OnCancel();
506 autofillDialog_->PerformClose();
507 }
508
509 - (void)updateNotificationArea {
510 [mainContainer_ updateNotificationArea];
511 }
512
513 - (void)updateAccountChooser {
514 [accountChooser_ update];
515 [mainContainer_ updateLegalDocuments];
516
517 // For the duration of the loading shield, hide the main contents.
518 // This prevents the currently focused text field "shining through".
519 // No need to remember previous state, because the loading shield
520 // always flows through to the main container.
521 [loadingShieldController_ update];
522 [[mainContainer_ view] setHidden:![[loadingShieldController_ view] isHidden]];
523 }
524
525 - (void)updateButtonStrip {
526 [overlayController_ updateState];
527 }
528
529 - (void)updateSection:(autofill::DialogSection)section {
530 [[mainContainer_ sectionForId:section] update];
531 [mainContainer_ updateSaveInChrome];
532 }
533
534 - (void)fillSection:(autofill::DialogSection)section
535 forInput:(const autofill::DetailInput&)input {
536 [[mainContainer_ sectionForId:section] fillForInput:input];
537 [mainContainer_ updateSaveInChrome];
538 }
539
540 - (content::NavigationController*)showSignIn {
541 [self updateSignInSizeConstraints];
542 [signInContainer_ loadSignInPage];
543 [[mainContainer_ view] setHidden:YES];
544 [[signInContainer_ view] setHidden:NO];
545 [self requestRelayout];
546
547 return [signInContainer_ navigationController];
548 }
549
550 - (void)getInputs:(autofill::DetailOutputMap*)output
551 forSection:(autofill::DialogSection)section {
552 [[mainContainer_ sectionForId:section] getInputs:output];
553 }
554
555 - (NSString*)getCvc {
556 autofill::DialogSection section = autofill::SECTION_CC;
557 NSString* value = [[mainContainer_ sectionForId:section] suggestionText];
558 if (!value) {
559 section = autofill::SECTION_CC_BILLING;
560 value = [[mainContainer_ sectionForId:section] suggestionText];
561 }
562 return value;
563 }
564
565 - (BOOL)saveDetailsLocally {
566 return [mainContainer_ saveDetailsLocally];
567 }
568
569 - (void)hideSignIn {
570 [[signInContainer_ view] setHidden:YES];
571 [[mainContainer_ view] setHidden:NO];
572 [self requestRelayout];
573 }
574
575 - (void)modelChanged {
576 [mainContainer_ modelChanged];
577 }
578
579 - (void)updateErrorBubble {
580 [mainContainer_ updateErrorBubble];
581 }
582
583 - (void)onSignInResize:(NSSize)size {
584 [signInContainer_ setPreferredSize:size];
585 [self requestRelayout];
586 }
587
588 @end
589
590
591 @implementation AutofillDialogWindowController (TestableAutofillDialogView)
592
593 - (void)setTextContents:(NSString*)text
594 forInput:(const autofill::DetailInput&)input {
595 for (size_t i = autofill::SECTION_MIN; i <= autofill::SECTION_MAX; ++i) {
596 autofill::DialogSection section = static_cast<autofill::DialogSection>(i);
597 // TODO(groby): Need to find the section for an input directly - wasteful.
598 [[mainContainer_ sectionForId:section] setFieldValue:text forInput:input];
599 }
600 }
601
602 - (void)setTextContents:(NSString*)text
603 ofSuggestionForSection:(autofill::DialogSection)section {
604 [[mainContainer_ sectionForId:section] setSuggestionFieldValue:text];
605 }
606
607 - (void)activateFieldForInput:(const autofill::DetailInput&)input {
608 for (size_t i = autofill::SECTION_MIN; i <= autofill::SECTION_MAX; ++i) {
609 autofill::DialogSection section = static_cast<autofill::DialogSection>(i);
610 [[mainContainer_ sectionForId:section] activateFieldForInput:input];
611 }
612 }
613
614 - (content::WebContents*)getSignInWebContents {
615 return [signInContainer_ webContents];
616 }
617
618 - (BOOL)IsShowingOverlay {
619 return ![[overlayController_ view] isHidden];
620 }
621
622 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698