1// Copyright (c) 2011 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 "chrome/browser/ui/webui/constrained_html_ui.h"
6
7#import <Cocoa/Cocoa.h>
8
9#include "base/memory/scoped_nsobject.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/ui/cocoa/constrained_window_mac.h"
12#include "chrome/browser/ui/webui/html_dialog_ui.h"
13#include "chrome/browser/ui/webui/html_dialog_tab_contents_delegate.h"
14#include "content/browser/tab_contents/tab_contents.h"
15#include "ui/gfx/size.h"
16
17class ConstrainedHtmlDelegateMac :
18    public ConstrainedWindowMacDelegateCustomSheet,
19    public HtmlDialogTabContentsDelegate,
20    public ConstrainedHtmlUIDelegate {
21
22 public:
23  ConstrainedHtmlDelegateMac(Profile* profile,
24                             HtmlDialogUIDelegate* delegate);
25  ~ConstrainedHtmlDelegateMac() {}
26
27  // ConstrainedWindowMacDelegateCustomSheet -----------------------------------
28  virtual void DeleteDelegate() {
29    // From ConstrainedWindowMacDelegate: "you MUST close the sheet belonging to
30    // your delegate in this method."
31    if (is_sheet_open())
32      [NSApp endSheet:sheet()];
33    html_delegate_->OnDialogClosed("");
34    delete this;
35  }
36
37  // ConstrainedHtmlDelegate ---------------------------------------------------
38  virtual HtmlDialogUIDelegate* GetHtmlDialogUIDelegate();
39  virtual void OnDialogClose();
40
41  // HtmlDialogTabContentsDelegate ---------------------------------------------
42  void MoveContents(TabContents* source, const gfx::Rect& pos) {}
43  void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {}
44
45  void set_window(ConstrainedWindow* window) {
46    constrained_window_ = window;
47  }
48
49 private:
50  TabContents tab_contents_;  // Holds the HTML to be displayed in the sheet.
51  HtmlDialogUIDelegate* html_delegate_;  // weak.
52
53  // The constrained window that owns |this|. Saved here because it needs to be
54  // closed in response to the WebUI OnDialogClose callback.
55  ConstrainedWindow* constrained_window_;
56
57  DISALLOW_COPY_AND_ASSIGN(ConstrainedHtmlDelegateMac);
58};
59
60// The delegate used to forward events from the sheet to the constrained
61// window delegate. This bridge needs to be passed into the customsheet
62// to allow the HtmlDialog to know when the sheet closes.
63@interface ConstrainedHtmlDialogSheetCocoa : NSObject {
64  ConstrainedHtmlDelegateMac* constrainedHtmlDelegate_;  // weak
65}
66- (id)initWithConstrainedHtmlDelegateMac:
67    (ConstrainedHtmlDelegateMac*)ConstrainedHtmlDelegateMac;
68- (void)sheetDidEnd:(NSWindow*)sheet
69         returnCode:(int)returnCode
70        contextInfo:(void*)contextInfo;
71@end
72
73ConstrainedHtmlDelegateMac::ConstrainedHtmlDelegateMac(
74  Profile* profile,
75  HtmlDialogUIDelegate* delegate)
76  : HtmlDialogTabContentsDelegate(profile),
77    tab_contents_(profile, NULL, MSG_ROUTING_NONE, NULL, NULL),
78    html_delegate_(delegate),
79    constrained_window_(NULL) {
80  tab_contents_.set_delegate(this);
81
82  // Set |this| as a property on the tab contents so that the ConstrainedHtmlUI
83  // can get a reference to |this|.
84  ConstrainedHtmlUI::GetPropertyAccessor().SetProperty(
85      tab_contents_.property_bag(), this);
86
87  tab_contents_.controller().LoadURL(delegate->GetDialogContentURL(),
88                                     GURL(), PageTransition::START_PAGE);
89
90  // Create NSWindow to hold tab_contents in the constrained sheet:
91  gfx::Size size;
92  delegate->GetDialogSize(&size);
93  NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
94
95  // |window| is retained by the ConstrainedWindowMacDelegateCustomSheet when
96  // the sheet is initialized.
97  scoped_nsobject<NSWindow> window;
98  window.reset(
99      [[NSWindow alloc] initWithContentRect:frame
100                                  styleMask:NSTitledWindowMask
101                                    backing:NSBackingStoreBuffered
102                                      defer:YES]);
103
104  [window.get() setContentView:tab_contents_.GetNativeView()];
105
106  // Set the custom sheet to point to the new window.
107  ConstrainedWindowMacDelegateCustomSheet::init(
108      window.get(),
109      [[[ConstrainedHtmlDialogSheetCocoa alloc]
110          initWithConstrainedHtmlDelegateMac:this] autorelease],
111      @selector(sheetDidEnd:returnCode:contextInfo:));
112}
113
114HtmlDialogUIDelegate* ConstrainedHtmlDelegateMac::GetHtmlDialogUIDelegate() {
115  return html_delegate_;
116}
117
118void ConstrainedHtmlDelegateMac::OnDialogClose() {
119  DCHECK(constrained_window_);
120  if (constrained_window_)
121    constrained_window_->CloseConstrainedWindow();
122}
123
124// static
125ConstrainedWindow* ConstrainedHtmlUI::CreateConstrainedHtmlDialog(
126    Profile* profile,
127    HtmlDialogUIDelegate* delegate,
128    TabContents* overshadowed) {
129  // Deleted when ConstrainedHtmlDelegateMac::DeleteDelegate() runs.
130  ConstrainedHtmlDelegateMac* constrained_delegate =
131      new ConstrainedHtmlDelegateMac(profile, delegate);
132  // Deleted when ConstrainedHtmlDelegateMac::OnDialogClose() runs.
133  ConstrainedWindow* constrained_window =
134      overshadowed->CreateConstrainedDialog(constrained_delegate);
135  constrained_delegate->set_window(constrained_window);
136  return constrained_window;
137}
138
139@implementation ConstrainedHtmlDialogSheetCocoa
140
141- (id)initWithConstrainedHtmlDelegateMac:
142    (ConstrainedHtmlDelegateMac*)ConstrainedHtmlDelegateMac {
143  if ((self = [super init]))
144    constrainedHtmlDelegate_ = ConstrainedHtmlDelegateMac;
145  return self;
146}
147
148- (void)sheetDidEnd:(NSWindow*)sheet
149         returnCode:(int)returnCode
150        contextInfo:(void *)contextInfo {
151  [sheet orderOut:self];
152}
153
154@end
155