| OLD | NEW |
| 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/cocoa/web_intent_picker_cocoa.h" | 5 #include "chrome/browser/ui/cocoa/web_intent_picker_cocoa.h" |
| 6 | 6 |
| 7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
| 8 | 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/message_loop.h" |
| 9 #include "chrome/browser/profiles/profile.h" | 11 #include "chrome/browser/profiles/profile.h" |
| 10 #include "chrome/browser/ui/browser.h" | 12 #include "chrome/browser/ui/browser.h" |
| 11 #include "chrome/browser/ui/browser_window.h" | 13 #include "chrome/browser/ui/browser_window.h" |
| 12 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | 14 #import "chrome/browser/ui/cocoa/browser_window_controller.h" |
| 13 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" | 15 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" |
| 14 #import "chrome/browser/ui/cocoa/web_intent_bubble_controller.h" | 16 #import "chrome/browser/ui/cocoa/web_intent_bubble_controller.h" |
| 15 #include "chrome/browser/ui/intents/web_intent_inline_disposition_delegate.h" | 17 #include "chrome/browser/ui/intents/web_intent_inline_disposition_delegate.h" |
| 16 #include "chrome/browser/ui/intents/web_intent_picker.h" | 18 #include "chrome/browser/ui/intents/web_intent_picker.h" |
| 17 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h" | 19 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h" |
| 18 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 20 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 19 #include "content/public/browser/web_contents.h" | 21 #include "content/public/browser/web_contents.h" |
| 20 #include "skia/ext/skia_utils_mac.h" | 22 #include "skia/ext/skia_utils_mac.h" |
| 21 #include "ui/gfx/image/image.h" | 23 #include "ui/gfx/image/image.h" |
| 22 | 24 |
| 23 using content::WebContents; | 25 using content::WebContents; |
| 24 | 26 |
| 25 // static | 27 // static |
| 26 WebIntentPicker* WebIntentPicker::Create(Browser* browser, | 28 WebIntentPicker* WebIntentPicker::Create(Browser* browser, |
| 27 TabContentsWrapper* wrapper, | 29 TabContentsWrapper* wrapper, |
| 28 WebIntentPickerDelegate* delegate, | 30 WebIntentPickerDelegate* delegate, |
| 29 WebIntentPickerModel* model) { | 31 WebIntentPickerModel* model) { |
| 30 return new WebIntentPickerCocoa(browser, wrapper, delegate, model); | 32 return new WebIntentPickerCocoa(browser, wrapper, delegate, model); |
| 31 } | 33 } |
| 32 | 34 |
| 33 WebIntentPickerCocoa::WebIntentPickerCocoa() | 35 WebIntentPickerCocoa::WebIntentPickerCocoa() |
| 34 : delegate_(NULL), | 36 : delegate_(NULL), |
| 35 model_(NULL), | 37 model_(NULL), |
| 36 browser_(NULL), | 38 browser_(NULL), |
| 37 controller_(NULL) { | 39 controller_(nil), |
| 40 weak_ptr_factory_(this) { |
| 38 } | 41 } |
| 39 | 42 |
| 40 | 43 |
| 41 WebIntentPickerCocoa::WebIntentPickerCocoa(Browser* browser, | 44 WebIntentPickerCocoa::WebIntentPickerCocoa(Browser* browser, |
| 42 TabContentsWrapper* wrapper, | 45 TabContentsWrapper* wrapper, |
| 43 WebIntentPickerDelegate* delegate, | 46 WebIntentPickerDelegate* delegate, |
| 44 WebIntentPickerModel* model) | 47 WebIntentPickerModel* model) |
| 45 : delegate_(delegate), | 48 : delegate_(delegate), |
| 46 model_(model), | 49 model_(model), |
| 47 browser_(browser), | 50 browser_(browser), |
| 48 controller_(NULL) { | 51 controller_(nil), |
| 52 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
| 49 model_->set_observer(this); | 53 model_->set_observer(this); |
| 50 | 54 |
| 51 DCHECK(browser); | 55 DCHECK(browser); |
| 52 DCHECK(delegate); | 56 DCHECK(delegate); |
| 53 NSWindow* parentWindow = browser->window()->GetNativeHandle(); | 57 NSWindow* parentWindow = browser->window()->GetNativeHandle(); |
| 54 | 58 |
| 55 // Compute the anchor point, relative to location bar. | 59 // Compute the anchor point, relative to location bar. |
| 56 BrowserWindowController* controller = [parentWindow windowController]; | 60 BrowserWindowController* controller = [parentWindow windowController]; |
| 57 LocationBarViewMac* locationBar = [controller locationBarBridge]; | 61 LocationBarViewMac* locationBar = [controller locationBarBridge]; |
| 58 NSPoint anchor = locationBar->GetPageInfoBubblePoint(); | 62 NSPoint anchor = locationBar->GetPageInfoBubblePoint(); |
| 59 anchor = [browser->window()->GetNativeHandle() convertBaseToScreen:anchor]; | 63 anchor = [browser->window()->GetNativeHandle() convertBaseToScreen:anchor]; |
| 60 | 64 |
| 61 // The controller is deallocated when the window is closed, so no need to | 65 // The controller is deallocated when the window is closed, so no need to |
| 62 // worry about it here. | 66 // worry about it here. |
| 63 [[WebIntentBubbleController alloc] initWithPicker:this | 67 [[WebIntentBubbleController alloc] initWithPicker:this |
| 64 parentWindow:parentWindow | 68 parentWindow:parentWindow |
| 65 anchoredAt:anchor]; | 69 anchoredAt:anchor]; |
| 66 } | 70 } |
| 67 | 71 |
| 68 WebIntentPickerCocoa::~WebIntentPickerCocoa() { | 72 WebIntentPickerCocoa::~WebIntentPickerCocoa() { |
| 69 if (model_ != NULL) | 73 if (model_ != NULL) |
| 70 model_->set_observer(NULL); | 74 model_->set_observer(NULL); |
| 71 } | 75 } |
| 72 | 76 |
| 73 void WebIntentPickerCocoa::Close() { | 77 void WebIntentPickerCocoa::Close() { |
| 74 } | 78 } |
| 75 | 79 |
| 80 void WebIntentPickerCocoa::PerformDelayedLayout() { |
| 81 // Check to see if a layout has already been scheduled. |
| 82 if (weak_ptr_factory_.HasWeakPtrs()) |
| 83 return; |
| 84 |
| 85 // Delay performing layout by a second so that all the animations from |
| 86 // InfoBubbleWindow and origin updates from BaseBubbleController finish, so |
| 87 // that we don't all race trying to change the frame's origin. |
| 88 // |
| 89 // Using MessageLoop is superior here to |-performSelector:| because it will |
| 90 // not retain its target; if the child outlives its parent, zombies get left |
| 91 // behind (http://crbug.com/59619). This will cancel the scheduled task if |
| 92 // the controller get destroyed before the message |
| 93 // can be delivered. |
| 94 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| 95 base::Bind(&WebIntentPickerCocoa::PerformLayout, |
| 96 weak_ptr_factory_.GetWeakPtr()), |
| 97 100 /* milliseconds */); |
| 98 } |
| 99 |
| 100 void WebIntentPickerCocoa::PerformLayout() { |
| 101 DCHECK(controller_); |
| 102 // If the window is animating closed when this is called, the |
| 103 // animation could be holding the last reference to |controller_| |
| 104 // (and thus |this|). Pin it until the task is completed. |
| 105 scoped_nsobject<WebIntentBubbleController> keep_alive([controller_ retain]); |
| 106 [controller_ performLayoutWithModel:model_]; |
| 107 } |
| 108 |
| 76 void WebIntentPickerCocoa::OnModelChanged(WebIntentPickerModel* model) { | 109 void WebIntentPickerCocoa::OnModelChanged(WebIntentPickerModel* model) { |
| 77 DCHECK(controller_); | 110 PerformDelayedLayout(); |
| 78 scoped_nsobject<NSMutableArray> urlArray( | |
| 79 [[NSMutableArray alloc] initWithCapacity:model->GetItemCount()]); | |
| 80 | |
| 81 for (size_t i = 0; i < model->GetItemCount(); ++i) { | |
| 82 const WebIntentPickerModel::Item& item = model->GetItemAt(i); | |
| 83 | |
| 84 [urlArray addObject: | |
| 85 [NSString stringWithUTF8String:item.url.spec().c_str()]]; | |
| 86 [controller_ replaceImageAtIndex:i withImage:item.favicon.ToNSImage()]; | |
| 87 } | |
| 88 | |
| 89 [controller_ setServiceURLs:urlArray]; | |
| 90 } | 111 } |
| 91 | 112 |
| 92 void WebIntentPickerCocoa::OnFaviconChanged(WebIntentPickerModel* model, | 113 void WebIntentPickerCocoa::OnFaviconChanged(WebIntentPickerModel* model, |
| 93 size_t index) { | 114 size_t index) { |
| 94 DCHECK(controller_); | 115 // We don't handle individual icon changes - just redo the whole model. |
| 95 | 116 PerformDelayedLayout(); |
| 96 const WebIntentPickerModel::Item& item = model->GetItemAt(index); | |
| 97 [controller_ replaceImageAtIndex:index withImage:item.favicon.ToNSImage()]; | |
| 98 } | 117 } |
| 99 | 118 |
| 100 void WebIntentPickerCocoa::OnInlineDisposition(WebIntentPickerModel* model) { | 119 void WebIntentPickerCocoa::OnInlineDisposition(WebIntentPickerModel* model) { |
| 101 const WebIntentPickerModel::Item& item = model->GetItemAt( | 120 const WebIntentPickerModel::Item& item = model->GetItemAt( |
| 102 model->inline_disposition_index()); | 121 model->inline_disposition_index()); |
| 103 | 122 |
| 104 content::WebContents* web_contents = content::WebContents::Create( | 123 content::WebContents* web_contents = content::WebContents::Create( |
| 105 browser_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL); | 124 browser_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL); |
| 106 inline_disposition_tab_contents_.reset(new TabContentsWrapper(web_contents)); | 125 inline_disposition_tab_contents_.reset(new TabContentsWrapper(web_contents)); |
| 107 inline_disposition_delegate_.reset(new WebIntentInlineDispositionDelegate); | 126 inline_disposition_delegate_.reset(new WebIntentInlineDispositionDelegate); |
| 108 web_contents->SetDelegate(inline_disposition_delegate_.get()); | 127 web_contents->SetDelegate(inline_disposition_delegate_.get()); |
| 109 | 128 |
| 110 inline_disposition_tab_contents_->web_contents()->GetController().LoadURL( | 129 inline_disposition_tab_contents_->web_contents()->GetController().LoadURL( |
| 111 item.url, | 130 item.url, |
| 112 content::Referrer(), | 131 content::Referrer(), |
| 113 content::PAGE_TRANSITION_START_PAGE, | 132 content::PAGE_TRANSITION_START_PAGE, |
| 114 std::string()); | 133 std::string()); |
| 115 | 134 |
| 116 [controller_ setInlineDispositionTabContents: | 135 [controller_ setInlineDispositionTabContents: |
| 117 inline_disposition_tab_contents_.get()]; | 136 inline_disposition_tab_contents_.get()]; |
| 137 PerformDelayedLayout(); |
| 118 | 138 |
| 119 delegate_->OnInlineDispositionWebContentsCreated(web_contents); | 139 delegate_->OnInlineDispositionWebContentsCreated(web_contents); |
| 120 } | 140 } |
| 121 | 141 |
| 122 void WebIntentPickerCocoa::OnCancelled() { | 142 void WebIntentPickerCocoa::OnCancelled() { |
| 123 DCHECK(delegate_); | 143 DCHECK(delegate_); |
| 124 delegate_->OnCancelled(); | 144 delegate_->OnCancelled(); |
| 125 controller_ = NULL; // Controller will be unusable soon, abandon. | 145 controller_ = NULL; // Controller will be unusable soon, abandon. |
| 126 } | 146 } |
| 127 | 147 |
| 128 void WebIntentPickerCocoa::OnServiceChosen(size_t index) { | 148 void WebIntentPickerCocoa::OnServiceChosen(size_t index) { |
| 129 DCHECK(delegate_); | 149 DCHECK(delegate_); |
| 130 const WebIntentPickerModel::Item& item = model_->GetItemAt(index); | 150 const WebIntentPickerModel::Item& item = model_->GetItemAt(index); |
| 131 delegate_->OnServiceChosen(index, item.disposition); | 151 delegate_->OnServiceChosen(index, item.disposition); |
| 132 } | 152 } |
| 133 | 153 |
| 134 void WebIntentPickerCocoa::set_controller( | 154 void WebIntentPickerCocoa::set_controller( |
| 135 WebIntentBubbleController* controller) { | 155 WebIntentBubbleController* controller) { |
| 136 controller_ = controller; | 156 controller_ = controller; |
| 137 } | 157 } |
| OLD | NEW |