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

Side by Side Diff: chrome/browser/ui/views/website_settings/permission_prompt_impl.cc

Issue 2748443005: Rename website_settings UI folders to permission_bubble. (Closed)
Patch Set: Created 3 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
OLDNEW
(Empty)
1 // Copyright 2014 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/views/website_settings/permission_prompt_impl.h"
6
7 #include <stddef.h>
8
9 #include "base/macros.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/strings/string16.h"
12 #include "chrome/browser/permissions/permission_request.h"
13 #include "chrome/browser/platform_util.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_window.h"
17 #include "chrome/browser/ui/layout_constants.h"
18 #include "chrome/browser/ui/views/exclusive_access_bubble_views.h"
19 #include "chrome/browser/ui/views/harmony/layout_delegate.h"
20 #include "chrome/browser/ui/views/website_settings/permission_selector_row.h"
21 #include "chrome/browser/ui/views/website_settings/permission_selector_row_obser ver.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "components/strings/grit/components_strings.h"
24 #include "components/url_formatter/elide_url.h"
25 #include "ui/accessibility/ax_node_data.h"
26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/models/combobox_model.h"
28 #include "ui/base/resource/resource_bundle.h"
29 #include "ui/gfx/color_palette.h"
30 #include "ui/gfx/paint_vector_icon.h"
31 #include "ui/gfx/text_constants.h"
32 #include "ui/gfx/vector_icons_public.h"
33 #include "ui/views/background.h"
34 #include "ui/views/bubble/bubble_dialog_delegate.h"
35 #include "ui/views/bubble/bubble_frame_view.h"
36 #include "ui/views/controls/button/checkbox.h"
37 #include "ui/views/controls/button/menu_button.h"
38 #include "ui/views/controls/button/menu_button_listener.h"
39 #include "ui/views/controls/combobox/combobox.h"
40 #include "ui/views/controls/combobox/combobox_listener.h"
41 #include "ui/views/controls/label.h"
42 #include "ui/views/controls/menu/menu_runner.h"
43 #include "ui/views/layout/box_layout.h"
44 #include "ui/views/layout/grid_layout.h"
45 #include "ui/views/layout/layout_constants.h"
46
47 namespace {
48
49 // (Square) pixel size of icon.
50 const int kIconSize = 18;
51
52 } // namespace
53
54 // This class is a MenuButton which is given a PermissionMenuModel. It
55 // shows the current checked item in the menu model, and notifies its listener
56 // about any updates to the state of the selection.
57 // TODO(gbillock): refactor PermissionMenuButton to work like this and re-use?
58 class PermissionCombobox : public views::MenuButton,
59 public views::MenuButtonListener {
60 public:
61 // Get notifications when the selection changes.
62 class Listener {
63 public:
64 virtual void PermissionSelectionChanged(int index, bool allowed) = 0;
65 };
66
67 PermissionCombobox(Profile* profile,
68 Listener* listener,
69 int index,
70 const GURL& url,
71 ContentSetting setting);
72 ~PermissionCombobox() override;
73
74 int index() const { return index_; }
75
76 void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
77
78 // MenuButtonListener:
79 void OnMenuButtonClicked(views::MenuButton* source,
80 const gfx::Point& point,
81 const ui::Event* event) override;
82
83 // Callback when a permission's setting is changed.
84 void PermissionChanged(const WebsiteSettingsUI::PermissionInfo& permission);
85
86 private:
87 int index_;
88 Listener* listener_;
89 std::unique_ptr<PermissionMenuModel> model_;
90 std::unique_ptr<views::MenuRunner> menu_runner_;
91 };
92
93 PermissionCombobox::PermissionCombobox(Profile* profile,
94 Listener* listener,
95 int index,
96 const GURL& url,
97 ContentSetting setting)
98 : MenuButton(base::string16(), this, true),
99 index_(index),
100 listener_(listener),
101 model_(new PermissionMenuModel(
102 profile,
103 url,
104 setting,
105 base::Bind(&PermissionCombobox::PermissionChanged,
106 base::Unretained(this)))) {
107 SetText(model_->GetLabelAt(model_->GetIndexOfCommandId(setting)));
108 SizeToPreferredSize();
109 }
110
111 PermissionCombobox::~PermissionCombobox() {}
112
113 void PermissionCombobox::GetAccessibleNodeData(ui::AXNodeData* node_data) {
114 MenuButton::GetAccessibleNodeData(node_data);
115 node_data->SetValue(GetText());
116 }
117
118 void PermissionCombobox::OnMenuButtonClicked(views::MenuButton* source,
119 const gfx::Point& point,
120 const ui::Event* event) {
121 menu_runner_.reset(new views::MenuRunner(
122 model_.get(),
123 views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::ASYNC));
124
125 gfx::Point p(point);
126 p.Offset(-source->width(), 0);
127 menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(), this,
128 gfx::Rect(p, gfx::Size()), views::MENU_ANCHOR_TOPLEFT,
129 ui::MENU_SOURCE_NONE);
130 }
131
132 void PermissionCombobox::PermissionChanged(
133 const WebsiteSettingsUI::PermissionInfo& permission) {
134 SetText(model_->GetLabelAt(model_->GetIndexOfCommandId(permission.setting)));
135 SizeToPreferredSize();
136
137 listener_->PermissionSelectionChanged(
138 index_, permission.setting == CONTENT_SETTING_ALLOW);
139 }
140
141 ///////////////////////////////////////////////////////////////////////////////
142 // View implementation for the permissions bubble.
143 class PermissionsBubbleDialogDelegateView
144 : public views::BubbleDialogDelegateView,
145 public PermissionCombobox::Listener {
146 public:
147 PermissionsBubbleDialogDelegateView(
148 PermissionPromptImpl* owner,
149 const std::vector<PermissionRequest*>& requests,
150 const std::vector<bool>& accept_state);
151 ~PermissionsBubbleDialogDelegateView() override;
152
153 void CloseBubble();
154 void SizeToContents();
155
156 // BubbleDialogDelegateView:
157 bool ShouldShowCloseButton() const override;
158 const gfx::FontList& GetTitleFontList() const override;
159 base::string16 GetWindowTitle() const override;
160 void OnWidgetDestroying(views::Widget* widget) override;
161 gfx::Size GetPreferredSize() const override;
162 void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
163 bool Cancel() override;
164 bool Accept() override;
165 bool Close() override;
166 int GetDefaultDialogButton() const override;
167 int GetDialogButtons() const override;
168 base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
169
170 // PermissionCombobox::Listener:
171 void PermissionSelectionChanged(int index, bool allowed) override;
172
173 // Updates the anchor's arrow and view. Also repositions the bubble so it's
174 // displayed in the correct location.
175 void UpdateAnchor(views::View* anchor_view,
176 const gfx::Point& anchor_point,
177 views::BubbleBorder::Arrow anchor_arrow);
178
179 private:
180 PermissionPromptImpl* owner_;
181 bool multiple_requests_;
182 base::string16 display_origin_;
183 std::unique_ptr<PermissionMenuModel> menu_button_model_;
184 std::vector<PermissionCombobox*> customize_comboboxes_;
185 views::Checkbox* persist_checkbox_;
186
187 DISALLOW_COPY_AND_ASSIGN(PermissionsBubbleDialogDelegateView);
188 };
189
190 PermissionsBubbleDialogDelegateView::PermissionsBubbleDialogDelegateView(
191 PermissionPromptImpl* owner,
192 const std::vector<PermissionRequest*>& requests,
193 const std::vector<bool>& accept_state)
194 : owner_(owner),
195 multiple_requests_(requests.size() > 1),
196 persist_checkbox_(nullptr) {
197 DCHECK(!requests.empty());
198
199 set_close_on_deactivate(false);
200
201 LayoutDelegate* layout_delegate = LayoutDelegate::Get();
202 SetLayoutManager(
203 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0,
204 layout_delegate->GetMetric(
205 LayoutDelegate::Metric::
206 RELATED_CONTROL_VERTICAL_SPACING)));
207
208 display_origin_ = url_formatter::FormatUrlForSecurityDisplay(
209 requests[0]->GetOrigin(),
210 url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);
211
212 bool show_persistence_toggle = true;
213 for (size_t index = 0; index < requests.size(); index++) {
214 DCHECK(index < accept_state.size());
215 // The row is laid out containing a leading-aligned label area and a
216 // trailing column which will be filled if there are multiple permission
217 // requests.
218 views::View* row = new views::View();
219 views::GridLayout* row_layout = new views::GridLayout(row);
220 row->SetLayoutManager(row_layout);
221 views::ColumnSet* columns = row_layout->AddColumnSet(0);
222 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL,
223 0, views::GridLayout::USE_PREF, 0, 0);
224 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::FILL,
225 100, views::GridLayout::USE_PREF, 0, 0);
226 row_layout->StartRow(0, 0);
227
228 views::View* label_container = new views::View();
229 int indent = layout_delegate->GetMetric(
230 LayoutDelegate::Metric::SUBSECTION_HORIZONTAL_INDENT);
231 label_container->SetLayoutManager(new views::BoxLayout(
232 views::BoxLayout::kHorizontal, indent, 0,
233 layout_delegate->GetMetric(
234 LayoutDelegate::Metric::RELATED_LABEL_HORIZONTAL_SPACING)));
235 views::ImageView* icon = new views::ImageView();
236 const gfx::VectorIcon& vector_id = requests[index]->GetIconId();
237 icon->SetImage(
238 gfx::CreateVectorIcon(vector_id, kIconSize, gfx::kChromeIconGrey));
239 icon->SetTooltipText(base::string16()); // Redundant with the text fragment
240 label_container->AddChildView(icon);
241 views::Label* label =
242 new views::Label(requests.at(index)->GetMessageTextFragment());
243 label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
244 label_container->AddChildView(label);
245 row_layout->AddView(label_container);
246
247 // Only show the toggle if every request wants to show it.
248 show_persistence_toggle = show_persistence_toggle &&
249 requests[index]->ShouldShowPersistenceToggle();
250 if (requests.size() > 1) {
251 PermissionCombobox* combobox = new PermissionCombobox(
252 owner->GetProfile(), this, index, requests[index]->GetOrigin(),
253 accept_state[index] ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK);
254 row_layout->AddView(combobox);
255 customize_comboboxes_.push_back(combobox);
256 } else {
257 row_layout->AddView(new views::View());
258 }
259
260 AddChildView(row);
261 }
262
263 if (show_persistence_toggle) {
264 persist_checkbox_ = new views::Checkbox(
265 l10n_util::GetStringUTF16(IDS_PERMISSIONS_BUBBLE_PERSIST_TEXT));
266 persist_checkbox_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
267 persist_checkbox_->SetChecked(true);
268 AddChildView(persist_checkbox_);
269 }
270 }
271
272 PermissionsBubbleDialogDelegateView::~PermissionsBubbleDialogDelegateView() {
273 if (owner_)
274 owner_->Closing();
275 }
276
277 void PermissionsBubbleDialogDelegateView::CloseBubble() {
278 owner_ = nullptr;
279 GetWidget()->Close();
280 }
281
282 bool PermissionsBubbleDialogDelegateView::ShouldShowCloseButton() const {
283 return true;
284 }
285
286 const gfx::FontList& PermissionsBubbleDialogDelegateView::GetTitleFontList()
287 const {
288 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
289 return rb.GetFontList(ui::ResourceBundle::BaseFont);
290 }
291
292 base::string16 PermissionsBubbleDialogDelegateView::GetWindowTitle() const {
293 return l10n_util::GetStringFUTF16(IDS_PERMISSIONS_BUBBLE_PROMPT,
294 display_origin_);
295 }
296
297 void PermissionsBubbleDialogDelegateView::SizeToContents() {
298 BubbleDialogDelegateView::SizeToContents();
299 }
300
301 void PermissionsBubbleDialogDelegateView::OnWidgetDestroying(
302 views::Widget* widget) {
303 views::BubbleDialogDelegateView::OnWidgetDestroying(widget);
304 if (owner_) {
305 owner_->Closing();
306 owner_ = nullptr;
307 }
308 }
309
310 gfx::Size PermissionsBubbleDialogDelegateView::GetPreferredSize() const {
311 // TODO(estade): bubbles should default to this width.
312 const int kWidth = 320 - GetInsets().width();
313 return gfx::Size(kWidth, GetHeightForWidth(kWidth));
314 }
315
316 void PermissionsBubbleDialogDelegateView::GetAccessibleNodeData(
317 ui::AXNodeData* node_data) {
318 views::BubbleDialogDelegateView::GetAccessibleNodeData(node_data);
319 node_data->role = ui::AX_ROLE_ALERT_DIALOG;
320 }
321
322 int PermissionsBubbleDialogDelegateView::GetDefaultDialogButton() const {
323 // To prevent permissions being accepted accidentally, and as a security
324 // measure against crbug.com/619429, permission prompts should not be accepted
325 // as the default action.
326 return ui::DIALOG_BUTTON_NONE;
327 }
328
329 int PermissionsBubbleDialogDelegateView::GetDialogButtons() const {
330 int buttons = ui::DIALOG_BUTTON_OK;
331 if (!multiple_requests_)
332 buttons |= ui::DIALOG_BUTTON_CANCEL;
333 return buttons;
334 }
335
336 base::string16 PermissionsBubbleDialogDelegateView::GetDialogButtonLabel(
337 ui::DialogButton button) const {
338 if (button == ui::DIALOG_BUTTON_CANCEL)
339 return l10n_util::GetStringUTF16(IDS_PERMISSION_DENY);
340
341 // The text differs based on whether OK is the only visible button.
342 return l10n_util::GetStringUTF16(GetDialogButtons() == ui::DIALOG_BUTTON_OK
343 ? IDS_OK
344 : IDS_PERMISSION_ALLOW);
345 }
346
347 bool PermissionsBubbleDialogDelegateView::Cancel() {
348 if (owner_) {
349 owner_->TogglePersist(!persist_checkbox_ || persist_checkbox_->checked());
350 owner_->Deny();
351 }
352 return true;
353 }
354
355 bool PermissionsBubbleDialogDelegateView::Accept() {
356 if (owner_) {
357 owner_->TogglePersist(!persist_checkbox_ || persist_checkbox_->checked());
358 owner_->Accept();
359 }
360 return true;
361 }
362
363 bool PermissionsBubbleDialogDelegateView::Close() {
364 // Neither explicit accept nor explicit deny.
365 return true;
366 }
367
368 void PermissionsBubbleDialogDelegateView::PermissionSelectionChanged(
369 int index,
370 bool allowed) {
371 owner_->ToggleAccept(index, allowed);
372 }
373
374 void PermissionsBubbleDialogDelegateView::UpdateAnchor(
375 views::View* anchor_view,
376 const gfx::Point& anchor_point,
377 views::BubbleBorder::Arrow anchor_arrow) {
378 set_arrow(anchor_arrow);
379
380 // Update the border in the bubble: will either add or remove the arrow.
381 views::BubbleFrameView* frame =
382 views::BubbleDialogDelegateView::GetBubbleFrameView();
383 views::BubbleBorder::Arrow adjusted_arrow = anchor_arrow;
384 if (base::i18n::IsRTL())
385 adjusted_arrow = views::BubbleBorder::horizontal_mirror(adjusted_arrow);
386 frame->SetBubbleBorder(std::unique_ptr<views::BubbleBorder>(
387 new views::BubbleBorder(adjusted_arrow, shadow(), color())));
388
389 // Reposition the bubble based on the updated arrow and view.
390 SetAnchorView(anchor_view);
391 // The anchor rect is ignored unless |anchor_view| is nullptr.
392 SetAnchorRect(gfx::Rect(anchor_point, gfx::Size()));
393 }
394
395 //////////////////////////////////////////////////////////////////////////////
396 // PermissionPromptImpl
397
398 PermissionPromptImpl::PermissionPromptImpl(Browser* browser)
399 : browser_(browser),
400 delegate_(nullptr),
401 bubble_delegate_(nullptr) {}
402
403 PermissionPromptImpl::~PermissionPromptImpl() {
404 }
405
406 void PermissionPromptImpl::SetDelegate(Delegate* delegate) {
407 delegate_ = delegate;
408 }
409
410 void PermissionPromptImpl::Show(const std::vector<PermissionRequest*>& requests,
411 const std::vector<bool>& values) {
412 DCHECK(browser_);
413 DCHECK(browser_->window());
414
415 if (bubble_delegate_)
416 bubble_delegate_->CloseBubble();
417
418 bubble_delegate_ =
419 new PermissionsBubbleDialogDelegateView(this, requests, values);
420
421 // Set |parent_window| because some valid anchors can become hidden.
422 bubble_delegate_->set_parent_window(
423 platform_util::GetViewForWindow(browser_->window()->GetNativeWindow()));
424
425 // Compensate for vertical padding in the anchor view's image. Note this is
426 // ignored whenever the anchor view is null.
427 bubble_delegate_->set_anchor_view_insets(gfx::Insets(
428 GetLayoutConstant(LOCATION_BAR_BUBBLE_ANCHOR_VERTICAL_INSET), 0));
429
430 views::BubbleDialogDelegateView::CreateBubble(bubble_delegate_)->Show();
431 bubble_delegate_->SizeToContents();
432
433 bubble_delegate_->UpdateAnchor(GetAnchorView(),
434 GetAnchorPoint(),
435 GetAnchorArrow());
436 }
437
438 bool PermissionPromptImpl::CanAcceptRequestUpdate() {
439 return !(bubble_delegate_ && bubble_delegate_->IsMouseHovered());
440 }
441
442 void PermissionPromptImpl::Hide() {
443 if (bubble_delegate_) {
444 bubble_delegate_->CloseBubble();
445 bubble_delegate_ = nullptr;
446 }
447 }
448
449 bool PermissionPromptImpl::IsVisible() {
450 return bubble_delegate_ != nullptr;
451 }
452
453 void PermissionPromptImpl::UpdateAnchorPosition() {
454 DCHECK(browser_);
455 DCHECK(browser_->window());
456
457 if (IsVisible()) {
458 bubble_delegate_->set_parent_window(
459 platform_util::GetViewForWindow(browser_->window()->GetNativeWindow()));
460 bubble_delegate_->UpdateAnchor(GetAnchorView(),
461 GetAnchorPoint(),
462 GetAnchorArrow());
463 }
464 }
465
466 gfx::NativeWindow PermissionPromptImpl::GetNativeWindow() {
467 if (bubble_delegate_ && bubble_delegate_->GetWidget())
468 return bubble_delegate_->GetWidget()->GetNativeWindow();
469 return nullptr;
470 }
471
472 void PermissionPromptImpl::Closing() {
473 if (bubble_delegate_)
474 bubble_delegate_ = nullptr;
475 if (delegate_)
476 delegate_->Closing();
477 }
478
479 void PermissionPromptImpl::ToggleAccept(int index, bool value) {
480 if (delegate_)
481 delegate_->ToggleAccept(index, value);
482 }
483
484 void PermissionPromptImpl::TogglePersist(bool value) {
485 if (delegate_)
486 delegate_->TogglePersist(value);
487 }
488
489 void PermissionPromptImpl::Accept() {
490 if (delegate_)
491 delegate_->Accept();
492 }
493
494 void PermissionPromptImpl::Deny() {
495 if (delegate_)
496 delegate_->Deny();
497 }
498
499 Profile* PermissionPromptImpl::GetProfile() {
500 return browser_->profile();
501 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698