OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/cocoa/web_intent_picker_cocoa.h" | |
6 | |
7 #import <Cocoa/Cocoa.h> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/message_loop.h" | |
11 #include "base/sys_string_conversions.h" | |
12 #include "chrome/browser/profiles/profile.h" | |
13 #include "chrome/browser/tab_contents/tab_util.h" | |
14 #include "chrome/browser/ui/browser_finder.h" | |
15 #include "chrome/browser/ui/browser_window.h" | |
16 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | |
17 #include "chrome/browser/ui/cocoa/constrained_window_mac.h" | |
18 #include "chrome/browser/ui/cocoa/intents/web_intent_picker_cocoa2.h" | |
19 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" | |
20 #import "chrome/browser/ui/cocoa/web_intent_sheet_controller.h" | |
21 #include "chrome/browser/ui/intents/web_intent_inline_disposition_delegate.h" | |
22 #include "chrome/browser/ui/intents/web_intent_picker.h" | |
23 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h" | |
24 #include "chrome/common/chrome_switches.h" | |
25 #include "content/public/browser/web_contents.h" | |
26 #include "ipc/ipc_message.h" | |
27 #include "skia/ext/skia_utils_mac.h" | |
28 #include "ui/gfx/image/image.h" | |
29 | |
30 using content::WebContents; | |
31 | |
32 namespace { | |
33 | |
34 // Since any delegates for constrained windows are tasked with deleting | |
35 // themselves, and the WebIntentPicker needs to live longer than the | |
36 // constrained window, we need this forwarding class. | |
37 class ConstrainedPickerSheetDelegate : | |
38 public ConstrainedWindowMacDelegateCustomSheet { | |
39 public: | |
40 ConstrainedPickerSheetDelegate( | |
41 WebIntentPickerCocoa* picker, | |
42 WebIntentPickerSheetController* sheet_controller); | |
43 virtual ~ConstrainedPickerSheetDelegate() {} | |
44 | |
45 // ConstrainedWindowMacDelegateCustomSheet interface | |
46 virtual void DeleteDelegate() OVERRIDE; | |
47 | |
48 private: | |
49 WebIntentPickerCocoa* picker_; // Weak reference to picker | |
50 | |
51 DISALLOW_COPY_AND_ASSIGN(ConstrainedPickerSheetDelegate); | |
52 }; | |
53 | |
54 ConstrainedPickerSheetDelegate::ConstrainedPickerSheetDelegate( | |
55 WebIntentPickerCocoa* picker, | |
56 WebIntentPickerSheetController* sheet_controller) | |
57 : picker_(picker) { | |
58 init([sheet_controller window], sheet_controller, | |
59 @selector(sheetDidEnd:returnCode:contextInfo:)); | |
60 } | |
61 | |
62 void ConstrainedPickerSheetDelegate::DeleteDelegate() { | |
63 if (is_sheet_open()) | |
64 [NSApp endSheet:sheet()]; | |
65 | |
66 delete this; | |
67 } | |
68 | |
69 } // namespace | |
70 | |
71 // static | |
72 WebIntentPicker* WebIntentPicker::Create(content::WebContents* web_contents, | |
73 WebIntentPickerDelegate* delegate, | |
74 WebIntentPickerModel* model) { | |
75 if (chrome::UseChromeStyleDialogs()) | |
76 return new WebIntentPickerCocoa2(web_contents, delegate, model); | |
77 return new WebIntentPickerCocoa(web_contents, delegate, model); | |
78 } | |
79 | |
80 WebIntentPickerCocoa::WebIntentPickerCocoa() | |
81 : delegate_(NULL), | |
82 model_(NULL), | |
83 web_contents_(NULL), | |
84 sheet_controller_(nil), | |
85 service_invoked(false) { | |
86 } | |
87 | |
88 WebIntentPickerCocoa::WebIntentPickerCocoa(content::WebContents* web_contents, | |
89 WebIntentPickerDelegate* delegate, | |
90 WebIntentPickerModel* model) | |
91 : delegate_(delegate), | |
92 model_(model), | |
93 web_contents_(web_contents), | |
94 sheet_controller_(nil), | |
95 service_invoked(false) { | |
96 model_->set_observer(this); | |
97 | |
98 DCHECK(delegate); | |
99 DCHECK(web_contents); | |
100 | |
101 sheet_controller_ = [ | |
102 [WebIntentPickerSheetController alloc] initWithPicker:this]; | |
103 | |
104 // Deleted when ConstrainedPickerSheetDelegate::DeleteDelegate() runs. | |
105 ConstrainedPickerSheetDelegate* constrained_delegate = | |
106 new ConstrainedPickerSheetDelegate(this, sheet_controller_); | |
107 | |
108 window_ = new ConstrainedWindowMac(web_contents, constrained_delegate); | |
109 } | |
110 | |
111 WebIntentPickerCocoa::~WebIntentPickerCocoa() { | |
112 if (model_ != NULL) | |
113 model_->set_observer(NULL); | |
114 } | |
115 | |
116 void WebIntentPickerCocoa::OnSheetDidEnd(NSWindow* sheet) { | |
117 [sheet orderOut:sheet_controller_]; | |
118 if (window_) | |
119 window_->CloseConstrainedWindow(); | |
120 if (delegate_) | |
121 delegate_->OnClosing(); | |
122 } | |
123 | |
124 void WebIntentPickerCocoa::Close() { | |
125 DCHECK(sheet_controller_); | |
126 [sheet_controller_ closeSheet]; | |
127 | |
128 if (inline_disposition_web_contents_.get()) | |
129 inline_disposition_web_contents_->OnCloseStarted(); | |
130 } | |
131 | |
132 void WebIntentPickerCocoa::SetActionString(const string16& action_string) { | |
133 [sheet_controller_ setActionString:base::SysUTF16ToNSString(action_string)]; | |
134 } | |
135 | |
136 void WebIntentPickerCocoa::PerformLayout() { | |
137 DCHECK(sheet_controller_); | |
138 // If the window is animating closed when this is called, the | |
139 // animation could be holding the last reference to |controller_| | |
140 // (and thus |this|). Pin it until the task is completed. | |
141 scoped_nsobject<WebIntentPickerSheetController> | |
142 keep_alive([sheet_controller_ retain]); | |
143 [sheet_controller_ performLayoutWithModel:model_]; | |
144 } | |
145 | |
146 void WebIntentPickerCocoa::OnModelChanged(WebIntentPickerModel* model) { | |
147 PerformLayout(); | |
148 } | |
149 | |
150 void WebIntentPickerCocoa::OnFaviconChanged(WebIntentPickerModel* model, | |
151 size_t index) { | |
152 // We don't handle individual icon changes - just redo the whole model. | |
153 PerformLayout(); | |
154 } | |
155 | |
156 void WebIntentPickerCocoa::OnExtensionIconChanged( | |
157 WebIntentPickerModel* model, | |
158 const std::string& extension_id) { | |
159 // We don't handle individual icon changes - just redo the whole model. | |
160 PerformLayout(); | |
161 } | |
162 | |
163 void WebIntentPickerCocoa::OnInlineDisposition(const string16& title, | |
164 const GURL& url) { | |
165 DCHECK(delegate_); | |
166 Profile* profile = | |
167 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); | |
168 inline_disposition_web_contents_.reset( | |
169 delegate_->CreateWebContentsForInlineDisposition(profile, url)); | |
170 Browser* browser = browser::FindBrowserWithWebContents(web_contents_); | |
171 inline_disposition_delegate_.reset( | |
172 new WebIntentInlineDispositionDelegate( | |
173 this, inline_disposition_web_contents_.get(), browser)); | |
174 | |
175 inline_disposition_web_contents_->GetController().LoadURL( | |
176 url, | |
177 content::Referrer(), | |
178 content::PAGE_TRANSITION_AUTO_TOPLEVEL, | |
179 std::string()); | |
180 [sheet_controller_ setInlineDispositionTitle: | |
181 base::SysUTF16ToNSString(title)]; | |
182 [sheet_controller_ setInlineDispositionWebContents: | |
183 inline_disposition_web_contents_.get()]; | |
184 PerformLayout(); | |
185 } | |
186 | |
187 void WebIntentPickerCocoa::OnCancelled() { | |
188 DCHECK(delegate_); | |
189 if (!service_invoked) | |
190 delegate_->OnUserCancelledPickerDialog(); | |
191 delegate_->OnClosing(); | |
192 MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
193 } | |
194 | |
195 void WebIntentPickerCocoa::OnServiceChosen(size_t index) { | |
196 DCHECK(delegate_); | |
197 const WebIntentPickerModel::InstalledService& installed_service = | |
198 model_->GetInstalledServiceAt(index); | |
199 service_invoked = true; | |
200 delegate_->OnServiceChosen(installed_service.url, | |
201 installed_service.disposition, | |
202 WebIntentPickerDelegate::kEnableDefaults); | |
203 } | |
204 | |
205 void WebIntentPickerCocoa::OnExtensionInstallRequested( | |
206 const std::string& extension_id) { | |
207 DCHECK(delegate_); | |
208 delegate_->OnExtensionInstallRequested(extension_id); | |
209 } | |
210 | |
211 void WebIntentPickerCocoa::OnExtensionInstallSuccess(const std::string& id) { | |
212 DCHECK(sheet_controller_); | |
213 [sheet_controller_ stopThrobber]; | |
214 } | |
215 | |
216 void WebIntentPickerCocoa::OnExtensionInstallFailure(const std::string& id) { | |
217 // TODO(groby): What to do on failure? (See also binji for views/gtk) | |
218 DCHECK(sheet_controller_); | |
219 [sheet_controller_ stopThrobber]; | |
220 } | |
221 | |
222 void WebIntentPickerCocoa::OnInlineDispositionAutoResize( | |
223 const gfx::Size& size) { | |
224 DCHECK(sheet_controller_); | |
225 NSSize inline_content_size = NSMakeSize(size.width(), size.height()); | |
226 [sheet_controller_ setInlineDispositionFrameSize:inline_content_size]; | |
227 } | |
228 | |
229 void WebIntentPickerCocoa::OnPendingAsyncCompleted() { | |
230 } | |
231 | |
232 void WebIntentPickerCocoa::InvalidateDelegate() { | |
233 delegate_ = NULL; | |
234 } | |
235 | |
236 void WebIntentPickerCocoa::OnExtensionLinkClicked( | |
237 const std::string& id, | |
238 WindowOpenDisposition disposition) { | |
239 DCHECK(delegate_); | |
240 delegate_->OnExtensionLinkClicked(id, disposition); | |
241 } | |
242 | |
243 void WebIntentPickerCocoa::OnSuggestionsLinkClicked( | |
244 WindowOpenDisposition disposition) { | |
245 DCHECK(delegate_); | |
246 delegate_->OnSuggestionsLinkClicked(disposition); | |
247 } | |
248 | |
249 void WebIntentPickerCocoa::OnChooseAnotherService() { | |
250 DCHECK(delegate_); | |
251 delegate_->OnChooseAnotherService(); | |
252 inline_disposition_web_contents_.reset(); | |
253 inline_disposition_delegate_.reset(); | |
254 [sheet_controller_ setInlineDispositionWebContents:NULL]; | |
255 PerformLayout(); | |
256 } | |
OLD | NEW |