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

Side by Side Diff: chrome/browser/ui/intents/web_intent_picker_controller.cc

Issue 9148032: [Web Intents] Refactor picker to use WebIntentPickerModel. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: groby's fix Created 8 years, 10 months 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) 2012 The Chromium Authors. All rights reserved. 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 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/intents/web_intent_picker_controller.h" 5 #include "chrome/browser/ui/intents/web_intent_picker_controller.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
11 #include "chrome/browser/ui/browser.h" 11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/favicon/favicon_service.h" 12 #include "chrome/browser/favicon/favicon_service.h"
13 #include "chrome/browser/intents/web_intents_registry.h" 13 #include "chrome/browser/intents/web_intents_registry.h"
14 #include "chrome/browser/intents/web_intents_registry_factory.h" 14 #include "chrome/browser/intents/web_intents_registry_factory.h"
15 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/tabs/tab_strip_model.h" 16 #include "chrome/browser/tabs/tab_strip_model.h"
17 #include "chrome/browser/ui/browser_navigator.h" 17 #include "chrome/browser/ui/browser_navigator.h"
18 #include "chrome/browser/ui/intents/web_intent_picker.h" 18 #include "chrome/browser/ui/intents/web_intent_picker.h"
19 #include "chrome/browser/ui/intents/web_intent_picker_factory.h" 19 #include "chrome/browser/ui/intents/web_intent_picker_model.h"
20 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 20 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
21 #include "chrome/browser/webdata/web_data_service.h" 21 #include "chrome/browser/webdata/web_data_service.h"
22 #include "chrome/common/chrome_notification_types.h" 22 #include "chrome/common/chrome_notification_types.h"
23 #include "content/browser/intents/intent_injector.h" 23 #include "content/browser/intents/intent_injector.h"
24 #include "content/public/browser/notification_source.h" 24 #include "content/public/browser/notification_source.h"
25 #include "content/public/browser/web_contents.h" 25 #include "content/public/browser/web_contents.h"
26 #include "content/public/browser/web_intents_dispatcher.h" 26 #include "content/public/browser/web_intents_dispatcher.h"
27 #include "ui/gfx/codec/png_codec.h" 27 #include "ui/gfx/codec/png_codec.h"
28 #include "ui/gfx/image/image.h"
28 #include "webkit/glue/web_intent_service_data.h" 29 #include "webkit/glue/web_intent_service_data.h"
29 30
30 using content::NavigationController;
31 using content::WebContents;
32
33 namespace { 31 namespace {
34 32
35 // Gets the favicon service for the profile in |tab_contents|. 33 // Gets the favicon service for the profile in |tab_contents|.
36 FaviconService* GetFaviconService(TabContentsWrapper* wrapper) { 34 FaviconService* GetFaviconService(TabContentsWrapper* wrapper) {
37 return wrapper->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS); 35 return wrapper->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS);
38 } 36 }
39 37
40 // Gets the web intents registry for the profile in |tab_contents|. 38 // Gets the web intents registry for the profile in |tab_contents|.
41 WebIntentsRegistry* GetWebIntentsRegistry(TabContentsWrapper* wrapper) { 39 WebIntentsRegistry* GetWebIntentsRegistry(TabContentsWrapper* wrapper) {
42 return WebIntentsRegistryFactory::GetForProfile(wrapper->profile()); 40 return WebIntentsRegistryFactory::GetForProfile(wrapper->profile());
43 } 41 }
44 42
43 WebIntentPickerModel::Disposition ConvertDisposition(
44 webkit_glue::WebIntentServiceData::Disposition disposition) {
45 switch (disposition) {
46 case webkit_glue::WebIntentServiceData::DISPOSITION_INLINE:
47 return WebIntentPickerModel::DISPOSITION_INLINE;
48 case webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW:
49 return WebIntentPickerModel::DISPOSITION_WINDOW;
50 default:
51 NOTREACHED();
52 return WebIntentPickerModel::DISPOSITION_WINDOW;
53 }
54 }
55
45 } // namespace 56 } // namespace
46 57
47 // A class that asynchronously fetches web intent data from the web intents 58 // A class that asynchronously fetches web intent data from the web intents
48 // registry. 59 // registry.
49 class WebIntentPickerController::WebIntentDataFetcher 60 class WebIntentPickerController::WebIntentDataFetcher
50 : public WebIntentsRegistry::Consumer { 61 : public WebIntentsRegistry::Consumer {
51 public: 62 public:
52 WebIntentDataFetcher(WebIntentPickerController* controller, 63 WebIntentDataFetcher(WebIntentPickerController* controller,
53 WebIntentsRegistry* web_intents_registry); 64 WebIntentsRegistry* web_intents_registry);
54 ~WebIntentDataFetcher(); 65 ~WebIntentDataFetcher();
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 // A weak pointer to the favicon service. 112 // A weak pointer to the favicon service.
102 FaviconService* favicon_service_; 113 FaviconService* favicon_service_;
103 114
104 // The Consumer to handle asynchronous favicon requests. 115 // The Consumer to handle asynchronous favicon requests.
105 CancelableRequestConsumerTSimple<size_t> load_consumer_; 116 CancelableRequestConsumerTSimple<size_t> load_consumer_;
106 117
107 DISALLOW_COPY_AND_ASSIGN(FaviconFetcher); 118 DISALLOW_COPY_AND_ASSIGN(FaviconFetcher);
108 }; 119 };
109 120
110 WebIntentPickerController::WebIntentPickerController( 121 WebIntentPickerController::WebIntentPickerController(
111 TabContentsWrapper* wrapper, 122 TabContentsWrapper* wrapper)
112 WebIntentPickerFactory* factory) 123 : wrapper_(wrapper),
113 : wrapper_(wrapper), 124 web_intent_data_fetcher_(
114 picker_factory_(factory), 125 new WebIntentDataFetcher(this, GetWebIntentsRegistry(wrapper))),
115 web_intent_data_fetcher_( 126 favicon_fetcher_(new FaviconFetcher(this, GetFaviconService(wrapper))),
116 new WebIntentDataFetcher(this, 127 picker_(NULL),
117 GetWebIntentsRegistry(wrapper))), 128 picker_model_(new WebIntentPickerModel()),
118 favicon_fetcher_( 129 pending_async_count_(0),
119 new FaviconFetcher(this, GetFaviconService(wrapper))), 130 picker_shown_(false),
120 picker_(NULL), 131 service_tab_(NULL) {
121 pending_async_count_(0), 132 content::NavigationController* controller =
122 service_tab_(NULL) { 133 &wrapper->web_contents()->GetController();
123 NavigationController* controller = &wrapper->web_contents()->GetController();
124 registrar_.Add(this, content::NOTIFICATION_LOAD_START, 134 registrar_.Add(this, content::NOTIFICATION_LOAD_START,
125 content::Source<NavigationController>(controller)); 135 content::Source<content::NavigationController>(controller));
126 registrar_.Add(this, content::NOTIFICATION_TAB_CLOSING, 136 registrar_.Add(this, content::NOTIFICATION_TAB_CLOSING,
127 content::Source<NavigationController>(controller)); 137 content::Source<content::NavigationController>(controller));
128 } 138 }
129 139
130 WebIntentPickerController::~WebIntentPickerController() { 140 WebIntentPickerController::~WebIntentPickerController() {
131 } 141 }
132 142
133 void WebIntentPickerController::SetIntentsDispatcher( 143 void WebIntentPickerController::SetIntentsDispatcher(
134 content::WebIntentsDispatcher* intents_dispatcher) { 144 content::WebIntentsDispatcher* intents_dispatcher) {
135 intents_dispatcher_.reset(intents_dispatcher); 145 intents_dispatcher_.reset(intents_dispatcher);
136 intents_dispatcher_->RegisterReplyNotification( 146 intents_dispatcher_->RegisterReplyNotification(
137 base::Bind(&WebIntentPickerController::OnSendReturnMessage, 147 base::Bind(&WebIntentPickerController::OnSendReturnMessage,
138 base::Unretained(this))); 148 base::Unretained(this)));
139 } 149 }
140 150
141 void WebIntentPickerController::ShowDialog(Browser* browser, 151 void WebIntentPickerController::ShowDialog(Browser* browser,
142 const string16& action, 152 const string16& action,
143 const string16& type) { 153 const string16& type) {
144 if (picker_ != NULL) 154 // Only show a picker once.
155 if (picker_shown_)
145 return; 156 return;
146 157
147 picker_ = picker_factory_->Create(browser, wrapper_, this); 158 picker_model_->Clear();
148 159
149 // TODO(binji) Remove this check when there are implementations of the picker 160 // If picker is non-NULL, it was set by a test.
150 // for windows and mac. 161 if (picker_ == NULL) {
151 if (picker_ == NULL) 162 picker_ = WebIntentPicker::Create(browser, wrapper_, this,
152 return; 163 picker_model_.get());
164 }
153 165
166 picker_shown_ = true;
154 web_intent_data_fetcher_->Fetch(action, type); 167 web_intent_data_fetcher_->Fetch(action, type);
155 } 168 }
156 169
157 void WebIntentPickerController::Observe( 170 void WebIntentPickerController::Observe(
158 int type, 171 int type,
159 const content::NotificationSource& source, 172 const content::NotificationSource& source,
160 const content::NotificationDetails& details) { 173 const content::NotificationDetails& details) {
161 DCHECK(type == content::NOTIFICATION_LOAD_START || 174 DCHECK(type == content::NOTIFICATION_LOAD_START ||
162 type == content::NOTIFICATION_TAB_CLOSING); 175 type == content::NOTIFICATION_TAB_CLOSING);
163 ClosePicker(); 176 ClosePicker();
164 } 177 }
165 178
166 void WebIntentPickerController::OnServiceChosen(size_t index) { 179 void WebIntentPickerController::OnServiceChosen(size_t index,
167 DCHECK(index < urls_.size()); 180 Disposition disposition) {
181 switch (disposition) {
182 case WebIntentPickerModel::DISPOSITION_INLINE:
183 // Set the model to inline disposition. It will notify the picker which
184 // will respond (via OnInlineDispositionWebContentsCreated) with the
185 // WebContents to dispatch the intent to.
186 picker_model_->SetInlineDisposition(index);
187 break;
168 188
169 bool inline_disposition = service_data_[index].disposition == 189 case WebIntentPickerModel::DISPOSITION_WINDOW: {
170 webkit_glue::WebIntentServiceData::DISPOSITION_INLINE; 190 // TODO(gbillock): This really only handles the 'window' disposition in a
171 WebContents* new_web_contents = NULL; 191 // quite prototype way. We need to flesh out what happens to the picker
172 if (inline_disposition) 192 // during the lifetime of the service url context, and that may mean we
173 new_web_contents = picker_->SetInlineDisposition(urls_[index]); 193 // need to pass more information into the injector to find the picker
194 // again and close it.
195 const WebIntentPickerModel::Item& item = picker_model_->GetItemAt(index);
174 196
175 if (new_web_contents == NULL) { 197 browser::NavigateParams params(NULL, item.url,
176 // TODO(gbillock): This really only handles the 'window' disposition in a 198 content::PAGE_TRANSITION_AUTO_BOOKMARK);
177 // quite prototype way. We need to flesh out what happens to the picker 199 params.disposition = NEW_FOREGROUND_TAB;
178 // during the lifetime of the service url context, and that may mean we 200 params.profile = wrapper_->profile();
179 // need to pass more information into the injector to find the picker again 201 browser::Navigate(&params);
180 // and close it. Also: the above conditional construction is just because 202 content::WebContents* web_contents =
181 // there isn't Mac/Win support yet. When that's there, it'll be an else. 203 params.target_contents->web_contents();
182 browser::NavigateParams params(NULL, urls_[index], 204 service_tab_ = web_contents;
183 content::PAGE_TRANSITION_AUTO_BOOKMARK);
184 params.disposition = NEW_FOREGROUND_TAB;
185 params.profile = wrapper_->profile();
186 browser::Navigate(&params);
187 new_web_contents = params.target_contents->web_contents();
188 service_tab_ = new_web_contents;
189 205
190 ClosePicker(); 206 ClosePicker();
207
208 intents_dispatcher_->DispatchIntent(web_contents);
209 break;
210 }
211
212 default:
213 NOTREACHED();
214 break;
191 } 215 }
216 }
192 217
193 intents_dispatcher_->DispatchIntent(new_web_contents); 218 void WebIntentPickerController::OnInlineDispositionWebContentsCreated(
219 content::WebContents* web_contents) {
220 if (web_contents) {
221 intents_dispatcher_->DispatchIntent(web_contents);
222 } else {
223 // TODO(binji): web_contents should never be NULL; it is in this case
224 // because views doesn't have an implementation for inline disposition yet.
225 // Remove this else when it does. In the meantime, just reforward as if it
226 // were the window disposition.
227 OnServiceChosen(picker_model_->inline_disposition_index(),
228 WebIntentPickerModel::DISPOSITION_WINDOW);
229 }
194 } 230 }
195 231
196 void WebIntentPickerController::OnCancelled() { 232 void WebIntentPickerController::OnCancelled() {
197 if (!intents_dispatcher_.get()) 233 if (!intents_dispatcher_.get())
198 return; 234 return;
199 235
200 if (service_tab_) { 236 if (service_tab_) {
201 intents_dispatcher_->SendReplyMessage( 237 intents_dispatcher_->SendReplyMessage(
202 webkit_glue::WEB_INTENT_SERVICE_TAB_CLOSED, string16()); 238 webkit_glue::WEB_INTENT_SERVICE_TAB_CLOSED, string16());
203 } else { 239 } else {
204 intents_dispatcher_->SendReplyMessage( 240 intents_dispatcher_->SendReplyMessage(
205 webkit_glue::WEB_INTENT_PICKER_CANCELLED, string16()); 241 webkit_glue::WEB_INTENT_PICKER_CANCELLED, string16());
206 } 242 }
207 243
208 ClosePicker(); 244 ClosePicker();
209 } 245 }
210 246
211 void WebIntentPickerController::OnClosing() { 247 void WebIntentPickerController::OnClosing() {
248 picker_shown_ = false;
249 picker_ = NULL;
212 } 250 }
213 251
214 void WebIntentPickerController::OnSendReturnMessage() { 252 void WebIntentPickerController::OnSendReturnMessage() {
215 ClosePicker(); 253 ClosePicker();
216 254
217 if (service_tab_) { 255 if (service_tab_) {
218 int index = TabStripModel::kNoTab; 256 int index = TabStripModel::kNoTab;
219 Browser* browser = Browser::GetBrowserForController( 257 Browser* browser = Browser::GetBrowserForController(
220 &service_tab_->GetController(), &index); 258 &service_tab_->GetController(), &index);
221 if (browser) { 259 if (browser) {
222 browser->tabstrip_model()->CloseTabContentsAt( 260 browser->tabstrip_model()->CloseTabContentsAt(
223 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); 261 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
224 } 262 }
225 service_tab_ = NULL; 263 service_tab_ = NULL;
226 } 264 }
227 } 265 }
228 266
229 void WebIntentPickerController::OnWebIntentDataAvailable( 267 void WebIntentPickerController::OnWebIntentDataAvailable(
230 const std::vector<webkit_glue::WebIntentServiceData>& services) { 268 const std::vector<webkit_glue::WebIntentServiceData>& services) {
231 urls_.clear(); 269 std::vector<GURL> urls;
232 for (size_t i = 0; i < services.size(); ++i) { 270 for (size_t i = 0; i < services.size(); ++i) {
233 urls_.push_back(services[i].service_url); 271 picker_model_->AddItem(services[i].title, services[i].service_url,
272 ConvertDisposition(services[i].disposition));
273 urls.push_back(services[i].service_url);
234 } 274 }
235 service_data_ = services;
236 275
237 // Tell the picker to initialize N urls to the default favicon 276 // Tell the picker to initialize N urls to the default favicon
238 picker_->SetServiceURLs(urls_); 277 favicon_fetcher_->Fetch(urls);
239 favicon_fetcher_->Fetch(urls_); 278 AsyncOperationFinished();
240 pending_async_count_--;
241 } 279 }
242 280
243 void WebIntentPickerController::OnFaviconDataAvailable( 281 void WebIntentPickerController::OnFaviconDataAvailable(size_t index,
244 size_t index, 282 const gfx::Image& icon) {
245 const SkBitmap& icon_bitmap) { 283 picker_model_->UpdateFaviconAt(index, icon);
246 picker_->SetServiceIcon(index, icon_bitmap); 284 AsyncOperationFinished();
247 pending_async_count_--;
248 } 285 }
249 286
250 void WebIntentPickerController::OnFaviconDataUnavailable(size_t index) { 287 void WebIntentPickerController::OnFaviconDataUnavailable(size_t index) {
251 picker_->SetDefaultServiceIcon(index); 288 AsyncOperationFinished();
252 pending_async_count_--; 289 }
290
291 void WebIntentPickerController::AsyncOperationFinished() {
292 if (--pending_async_count_ == 0) {
293 picker_->OnPendingAsyncCompleted();
294 }
253 } 295 }
254 296
255 void WebIntentPickerController::ClosePicker() { 297 void WebIntentPickerController::ClosePicker() {
256 if (picker_) { 298 if (picker_) {
257 picker_factory_->ClosePicker(picker_); 299 picker_->Close();
258 picker_ = NULL;
259 } 300 }
260 } 301 }
261 302
262 WebIntentPickerController::WebIntentDataFetcher::WebIntentDataFetcher( 303 WebIntentPickerController::WebIntentDataFetcher::WebIntentDataFetcher(
263 WebIntentPickerController* controller, 304 WebIntentPickerController* controller,
264 WebIntentsRegistry* web_intents_registry) 305 WebIntentsRegistry* web_intents_registry)
265 : controller_(controller), 306 : controller_(controller),
266 web_intents_registry_(web_intents_registry), 307 web_intents_registry_(web_intents_registry),
267 query_id_(-1) { 308 query_id_(-1) {
268 } 309 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 void WebIntentPickerController::FaviconFetcher::OnFaviconDataAvailable( 361 void WebIntentPickerController::FaviconFetcher::OnFaviconDataAvailable(
321 FaviconService::Handle handle, 362 FaviconService::Handle handle,
322 history::FaviconData favicon_data) { 363 history::FaviconData favicon_data) {
323 size_t index = load_consumer_.GetClientDataForCurrentRequest(); 364 size_t index = load_consumer_.GetClientDataForCurrentRequest();
324 if (favicon_data.is_valid()) { 365 if (favicon_data.is_valid()) {
325 SkBitmap icon_bitmap; 366 SkBitmap icon_bitmap;
326 367
327 if (gfx::PNGCodec::Decode(favicon_data.image_data->front(), 368 if (gfx::PNGCodec::Decode(favicon_data.image_data->front(),
328 favicon_data.image_data->size(), 369 favicon_data.image_data->size(),
329 &icon_bitmap)) { 370 &icon_bitmap)) {
330 controller_->OnFaviconDataAvailable(index, icon_bitmap); 371 gfx::Image icon_image(new SkBitmap(icon_bitmap));
372 controller_->OnFaviconDataAvailable(index, icon_image);
331 return; 373 return;
332 } 374 }
333 } 375 }
334 376
335 controller_->OnFaviconDataUnavailable(index); 377 controller_->OnFaviconDataUnavailable(index);
336 } 378 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698