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

Side by Side Diff: chrome/browser/ui/cocoa/web_intent_picker_cocoa.mm

Issue 9581041: Make web intents picker work as constrained dialog instead of InfoBubble (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 9 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/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" 9 #include "base/bind.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
11 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser.h" 12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_window.h" 13 #include "chrome/browser/ui/browser_window.h"
14 #import "chrome/browser/ui/cocoa/browser_window_controller.h" 14 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
15 #include "chrome/browser/ui/cocoa/constrained_window_mac.h"
15 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" 16 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
16 #import "chrome/browser/ui/cocoa/web_intent_bubble_controller.h" 17 #import "chrome/browser/ui/cocoa/web_intent_bubble_controller.h"
17 #include "chrome/browser/ui/intents/web_intent_inline_disposition_delegate.h" 18 #include "chrome/browser/ui/intents/web_intent_inline_disposition_delegate.h"
18 #include "chrome/browser/ui/intents/web_intent_picker.h" 19 #include "chrome/browser/ui/intents/web_intent_picker.h"
19 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h" 20 #include "chrome/browser/ui/intents/web_intent_picker_delegate.h"
20 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 21 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
21 #include "content/public/browser/web_contents.h" 22 #include "content/public/browser/web_contents.h"
22 #include "skia/ext/skia_utils_mac.h" 23 #include "skia/ext/skia_utils_mac.h"
23 #include "ui/gfx/image/image.h" 24 #include "ui/gfx/image/image.h"
24 25
25 using content::WebContents; 26 using content::WebContents;
26 27
28 namespace {
29
30 // Since any delegates for constrained windows are tasked with deleting
31 // themselves, and the WebIntentPicker needs to actually live longer than the
Nico 2012/03/03 06:13:49 s/actually//
groby-ooo-7-16 2012/03/03 23:41:49 Done.
32 // constrained window, we need this forwarding class
Nico 2012/03/03 06:13:49 .
groby-ooo-7-16 2012/03/03 23:41:49 Done.
33 class ConstrainedPickerSheetDelegate :
34 public ConstrainedWindowMacDelegateCustomSheet {
35 public:
36 ConstrainedPickerSheetDelegate(WebIntentPickerCocoa* picker,
37 WebIntentBubbleController* sheet_controller);
Nico 2012/03/03 06:13:49 indent 1 more
groby-ooo-7-16 2012/03/03 23:41:49 Done.
38 virtual ~ConstrainedPickerSheetDelegate() {}
39
40 // ConstrainedWindowMacDelegateCustomSheet interface
41 virtual void DeleteDelegate() OVERRIDE;
42
43 private:
44 WebIntentPickerCocoa* picker_; // Weak reference to picker
45
46 DISALLOW_COPY_AND_ASSIGN(ConstrainedPickerSheetDelegate);
47 };
48
49 ConstrainedPickerSheetDelegate::ConstrainedPickerSheetDelegate(
50 WebIntentPickerCocoa* picker, WebIntentBubbleController* sheet_controller)
51 : picker_(picker) {
52 init([sheet_controller window], sheet_controller,
53 @selector(sheetDidEnd:returnCode:contextInfo:));
54 set_sheet([sheet_controller window]);
55 }
56
57 void ConstrainedPickerSheetDelegate::DeleteDelegate() {
58 if (is_sheet_open())
59 [NSApp endSheet:sheet()];
60
61 if (picker_)
62 picker_->OnCancelled();
63
64 delete this;
65 }
66
67 } // namespace
68
27 // static 69 // static
28 WebIntentPicker* WebIntentPicker::Create(Browser* browser, 70 WebIntentPicker* WebIntentPicker::Create(Browser* browser,
29 TabContentsWrapper* wrapper, 71 TabContentsWrapper* wrapper,
30 WebIntentPickerDelegate* delegate, 72 WebIntentPickerDelegate* delegate,
31 WebIntentPickerModel* model) { 73 WebIntentPickerModel* model) {
32 return new WebIntentPickerCocoa(browser, wrapper, delegate, model); 74 return new WebIntentPickerCocoa(browser, wrapper, delegate, model);
33 } 75 }
34 76
35 WebIntentPickerCocoa::WebIntentPickerCocoa() 77 WebIntentPickerCocoa::WebIntentPickerCocoa()
36 : delegate_(NULL), 78 : delegate_(NULL),
37 model_(NULL), 79 model_(NULL),
38 browser_(NULL), 80 browser_(NULL),
39 controller_(nil), 81 sheet_controller_(nil),
40 weak_ptr_factory_(this),
41 service_invoked(false) { 82 service_invoked(false) {
42 } 83 }
43 84
44
45 WebIntentPickerCocoa::WebIntentPickerCocoa(Browser* browser, 85 WebIntentPickerCocoa::WebIntentPickerCocoa(Browser* browser,
46 TabContentsWrapper* wrapper, 86 TabContentsWrapper* wrapper,
47 WebIntentPickerDelegate* delegate, 87 WebIntentPickerDelegate* delegate,
48 WebIntentPickerModel* model) 88 WebIntentPickerModel* model)
49 : delegate_(delegate), 89 : delegate_(delegate),
50 model_(model), 90 model_(model),
51 browser_(browser), 91 browser_(browser),
52 controller_(nil), 92 sheet_controller_(nil),
53 weak_ptr_factory_(this), 93 service_invoked(false) {
54 service_invoked(false) {
55 model_->set_observer(this); 94 model_->set_observer(this);
56 95
57 DCHECK(browser); 96 DCHECK(browser);
58 DCHECK(delegate); 97 DCHECK(delegate);
59 NSWindow* parentWindow = browser->window()->GetNativeHandle(); 98 DCHECK(wrapper);
60 99
61 // Compute the anchor point, relative to location bar. 100 sheet_controller_ = [[WebIntentBubbleController alloc] initWithPicker:this];
62 BrowserWindowController* controller = [parentWindow windowController];
63 LocationBarViewMac* locationBar = [controller locationBarBridge];
64 NSPoint anchor = locationBar->GetPageInfoBubblePoint();
65 anchor = [browser->window()->GetNativeHandle() convertBaseToScreen:anchor];
66 101
67 // The controller is deallocated when the window is closed, so no need to 102 // Deleted when ConstrainedPickerSheetDelegate::DeleteDelegate() runs.
68 // worry about it here. 103 ConstrainedPickerSheetDelegate* constrained_delegate =
69 [[WebIntentBubbleController alloc] initWithPicker:this 104 new ConstrainedPickerSheetDelegate(this, sheet_controller_);
70 parentWindow:parentWindow 105
71 anchoredAt:anchor]; 106 window_ = new ConstrainedWindowMac(wrapper, constrained_delegate);
72 } 107 }
73 108
74 WebIntentPickerCocoa::~WebIntentPickerCocoa() { 109 WebIntentPickerCocoa::~WebIntentPickerCocoa() {
75 if (model_ != NULL) 110 if (model_ != NULL)
76 model_->set_observer(NULL); 111 model_->set_observer(NULL);
77 } 112 }
78 113
114 void WebIntentPickerCocoa::OnSheetDidEnd(NSWindow* sheet) {
115 [sheet orderOut:sheet_controller_];
116 if (window_)
117 window_->CloseConstrainedWindow();
118 }
119
79 void WebIntentPickerCocoa::Close() { 120 void WebIntentPickerCocoa::Close() {
80 DCHECK(controller_); 121 DCHECK(sheet_controller_);
81 [controller_ close]; 122 [sheet_controller_ closeSheet];
123
82 if (inline_disposition_tab_contents_.get()) 124 if (inline_disposition_tab_contents_.get())
83 inline_disposition_tab_contents_->web_contents()->OnCloseStarted(); 125 inline_disposition_tab_contents_->web_contents()->OnCloseStarted();
84 } 126 }
85 127
86 void WebIntentPickerCocoa::PerformDelayedLayout() {
87 // Check to see if a layout has already been scheduled.
88 if (weak_ptr_factory_.HasWeakPtrs())
89 return;
90
91 // Delay performing layout by a second so that all the animations from
92 // InfoBubbleWindow and origin updates from BaseBubbleController finish, so
93 // that we don't all race trying to change the frame's origin.
94 //
95 // Using MessageLoop is superior here to |-performSelector:| because it will
96 // not retain its target; if the child outlives its parent, zombies get left
97 // behind (http://crbug.com/59619). This will cancel the scheduled task if
98 // the controller get destroyed before the message
99 // can be delivered.
100 MessageLoop::current()->PostDelayedTask(FROM_HERE,
101 base::Bind(&WebIntentPickerCocoa::PerformLayout,
102 weak_ptr_factory_.GetWeakPtr()),
103 100 /* milliseconds */);
104 }
105
106 void WebIntentPickerCocoa::PerformLayout() { 128 void WebIntentPickerCocoa::PerformLayout() {
107 DCHECK(controller_); 129 DCHECK(sheet_controller_);
108 // If the window is animating closed when this is called, the 130 // If the window is animating closed when this is called, the
109 // animation could be holding the last reference to |controller_| 131 // animation could be holding the last reference to |controller_|
110 // (and thus |this|). Pin it until the task is completed. 132 // (and thus |this|). Pin it until the task is completed.
111 scoped_nsobject<WebIntentBubbleController> keep_alive([controller_ retain]); 133 scoped_nsobject<WebIntentBubbleController>
112 [controller_ performLayoutWithModel:model_]; 134 keep_alive([sheet_controller_ retain]);
135 [sheet_controller_ performLayoutWithModel:model_];
113 } 136 }
114 137
115 void WebIntentPickerCocoa::OnModelChanged(WebIntentPickerModel* model) { 138 void WebIntentPickerCocoa::OnModelChanged(WebIntentPickerModel* model) {
116 PerformDelayedLayout(); 139 PerformLayout();
117 } 140 }
118 141
119 void WebIntentPickerCocoa::OnFaviconChanged(WebIntentPickerModel* model, 142 void WebIntentPickerCocoa::OnFaviconChanged(WebIntentPickerModel* model,
120 size_t index) { 143 size_t index) {
121 // We don't handle individual icon changes - just redo the whole model. 144 // We don't handle individual icon changes - just redo the whole model.
122 PerformDelayedLayout(); 145 PerformLayout();
123 } 146 }
124 147
125 void WebIntentPickerCocoa::OnExtensionIconChanged( 148 void WebIntentPickerCocoa::OnExtensionIconChanged(
126 WebIntentPickerModel* model, 149 WebIntentPickerModel* model,
127 const string16& extension_id) { 150 const string16& extension_id) {
128 // TODO(binji): implement. 151 // TODO(binji): implement.
129 } 152 }
130 153
131 void WebIntentPickerCocoa::OnInlineDisposition(WebIntentPickerModel* model) { 154 void WebIntentPickerCocoa::OnInlineDisposition(WebIntentPickerModel* model) {
132 const WebIntentPickerModel::InstalledService& installed_service = 155 const WebIntentPickerModel::InstalledService& installed_service =
133 model->GetInstalledServiceAt(model->inline_disposition_index()); 156 model->GetInstalledServiceAt(model->inline_disposition_index());
134 157
135 content::WebContents* web_contents = content::WebContents::Create( 158 content::WebContents* web_contents = content::WebContents::Create(
136 browser_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL); 159 browser_->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL);
137 inline_disposition_tab_contents_.reset(new TabContentsWrapper(web_contents)); 160 inline_disposition_tab_contents_.reset(new TabContentsWrapper(web_contents));
138 inline_disposition_delegate_.reset(new WebIntentInlineDispositionDelegate); 161 inline_disposition_delegate_.reset(new WebIntentInlineDispositionDelegate);
139 web_contents->SetDelegate(inline_disposition_delegate_.get()); 162 web_contents->SetDelegate(inline_disposition_delegate_.get());
140 163
141 // Must call this immediately after WebContents creation to avoid race 164 // Must call this immediately after WebContents creation to avoid race
142 // with load. 165 // with load.
143 delegate_->OnInlineDispositionWebContentsCreated(web_contents); 166 delegate_->OnInlineDispositionWebContentsCreated(web_contents);
144 167
145 inline_disposition_tab_contents_->web_contents()->GetController().LoadURL( 168 inline_disposition_tab_contents_->web_contents()->GetController().LoadURL(
146 installed_service.url, 169 installed_service.url,
147 content::Referrer(), 170 content::Referrer(),
148 content::PAGE_TRANSITION_START_PAGE, 171 content::PAGE_TRANSITION_START_PAGE,
149 std::string()); 172 std::string());
150 173
151 [controller_ setInlineDispositionTabContents: 174 [sheet_controller_ setInlineDispositionTabContents:
152 inline_disposition_tab_contents_.get()]; 175 inline_disposition_tab_contents_.get()];
153 PerformDelayedLayout(); 176 PerformLayout();
154 } 177 }
155 178
156 void WebIntentPickerCocoa::OnCancelled() { 179 void WebIntentPickerCocoa::OnCancelled() {
157 DCHECK(delegate_); 180 DCHECK(delegate_);
158 if (!service_invoked) 181 if (!service_invoked)
159 delegate_->OnCancelled(); 182 delegate_->OnCancelled();
160 delegate_->OnClosing(); 183 delegate_->OnClosing();
161 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 184 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
162 } 185 }
163 186
164 void WebIntentPickerCocoa::OnServiceChosen(size_t index) { 187 void WebIntentPickerCocoa::OnServiceChosen(size_t index) {
165 DCHECK(delegate_); 188 DCHECK(delegate_);
166 const WebIntentPickerModel::InstalledService& installed_service = 189 const WebIntentPickerModel::InstalledService& installed_service =
167 model_->GetInstalledServiceAt(index); 190 model_->GetInstalledServiceAt(index);
168 service_invoked = true; 191 service_invoked = true;
169 delegate_->OnServiceChosen(index, installed_service.disposition); 192 delegate_->OnServiceChosen(index, installed_service.disposition);
170 } 193 }
171 194
172 void WebIntentPickerCocoa::set_controller(
173 WebIntentBubbleController* controller) {
174 controller_ = controller;
175 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698