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

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

Issue 2182883002: Permissions: Rename PermissionBubbleView to PermissionPromptInterface (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: thestig@ review Created 4 years, 4 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/permissions_bubble_view.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/views/exclusive_access_bubble_views.h"
18 #include "chrome/browser/ui/views/website_settings/permission_selector_view.h"
19 #include "chrome/browser/ui/views/website_settings/permission_selector_view_obse rver.h"
20 #include "chrome/grit/generated_resources.h"
21 #include "components/url_formatter/elide_url.h"
22 #include "grit/components_strings.h"
23 #include "ui/accessibility/ax_view_state.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/models/combobox_model.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "ui/gfx/color_palette.h"
28 #include "ui/gfx/paint_vector_icon.h"
29 #include "ui/gfx/text_constants.h"
30 #include "ui/gfx/vector_icons_public.h"
31 #include "ui/views/bubble/bubble_dialog_delegate.h"
32 #include "ui/views/bubble/bubble_frame_view.h"
33 #include "ui/views/controls/button/checkbox.h"
34 #include "ui/views/controls/button/menu_button.h"
35 #include "ui/views/controls/button/menu_button_listener.h"
36 #include "ui/views/controls/combobox/combobox.h"
37 #include "ui/views/controls/combobox/combobox_listener.h"
38 #include "ui/views/controls/label.h"
39 #include "ui/views/controls/menu/menu_runner.h"
40 #include "ui/views/layout/box_layout.h"
41 #include "ui/views/layout/grid_layout.h"
42 #include "ui/views/layout/layout_constants.h"
43
44 namespace {
45
46 // Spacing between major items should be 9px.
47 const int kItemMajorSpacing = 9;
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(Listener* listener,
68 int index,
69 const GURL& url,
70 ContentSetting setting);
71 ~PermissionCombobox() override;
72
73 int index() const { return index_; }
74
75 void GetAccessibleState(ui::AXViewState* state) override;
76
77 // MenuButtonListener:
78 void OnMenuButtonClicked(views::MenuButton* source,
79 const gfx::Point& point,
80 const ui::Event* event) override;
81
82 // Callback when a permission's setting is changed.
83 void PermissionChanged(const WebsiteSettingsUI::PermissionInfo& permission);
84
85 private:
86 int index_;
87 Listener* listener_;
88 std::unique_ptr<PermissionMenuModel> model_;
89 std::unique_ptr<views::MenuRunner> menu_runner_;
90 };
91
92 PermissionCombobox::PermissionCombobox(Listener* listener,
93 int index,
94 const GURL& url,
95 ContentSetting setting)
96 : MenuButton(base::string16(), this, true),
97 index_(index),
98 listener_(listener),
99 model_(new PermissionMenuModel(
100 url,
101 setting,
102 base::Bind(&PermissionCombobox::PermissionChanged,
103 base::Unretained(this)))) {
104 SetText(model_->GetLabelAt(model_->GetIndexOfCommandId(setting)));
105 SizeToPreferredSize();
106 }
107
108 PermissionCombobox::~PermissionCombobox() {}
109
110 void PermissionCombobox::GetAccessibleState(ui::AXViewState* state) {
111 MenuButton::GetAccessibleState(state);
112 state->value = GetText();
113 }
114
115 void PermissionCombobox::OnMenuButtonClicked(views::MenuButton* source,
116 const gfx::Point& point,
117 const ui::Event* event) {
118 menu_runner_.reset(
119 new views::MenuRunner(model_.get(), views::MenuRunner::HAS_MNEMONICS));
120
121 gfx::Point p(point);
122 p.Offset(-source->width(), 0);
123 if (menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(),
124 this,
125 gfx::Rect(p, gfx::Size()),
126 views::MENU_ANCHOR_TOPLEFT,
127 ui::MENU_SOURCE_NONE) ==
128 views::MenuRunner::MENU_DELETED) {
129 return;
130 }
131 }
132
133 void PermissionCombobox::PermissionChanged(
134 const WebsiteSettingsUI::PermissionInfo& permission) {
135 SetText(model_->GetLabelAt(model_->GetIndexOfCommandId(permission.setting)));
136 SizeToPreferredSize();
137
138 listener_->PermissionSelectionChanged(
139 index_, permission.setting == CONTENT_SETTING_ALLOW);
140 }
141
142 ///////////////////////////////////////////////////////////////////////////////
143 // View implementation for the permissions bubble.
144 class PermissionsBubbleDialogDelegateView
145 : public views::BubbleDialogDelegateView,
146 public PermissionCombobox::Listener {
147 public:
148 PermissionsBubbleDialogDelegateView(
149 PermissionBubbleViewViews* owner,
150 const std::vector<PermissionRequest*>& requests,
151 const std::vector<bool>& accept_state);
152 ~PermissionsBubbleDialogDelegateView() override;
153
154 void CloseBubble();
155 void SizeToContents();
156
157 // BubbleDialogDelegateView:
158 bool ShouldShowCloseButton() const override;
159 const gfx::FontList& GetTitleFontList() const override;
160 base::string16 GetWindowTitle() const override;
161 void OnWidgetDestroying(views::Widget* widget) override;
162 gfx::Size GetPreferredSize() const override;
163 void GetAccessibleState(ui::AXViewState* state) override;
164 bool Cancel() override;
165 bool Accept() override;
166 bool Close() 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 PermissionBubbleViewViews* 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
186 DISALLOW_COPY_AND_ASSIGN(PermissionsBubbleDialogDelegateView);
187 };
188
189 PermissionsBubbleDialogDelegateView::PermissionsBubbleDialogDelegateView(
190 PermissionBubbleViewViews* owner,
191 const std::vector<PermissionRequest*>& requests,
192 const std::vector<bool>& accept_state)
193 : owner_(owner),
194 multiple_requests_(requests.size() > 1) {
195 DCHECK(!requests.empty());
196
197 set_close_on_deactivate(false);
198
199 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0,
200 kItemMajorSpacing));
201
202 display_origin_ = url_formatter::FormatUrlForSecurityDisplay(
203 requests[0]->GetOrigin(),
204 url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);
205
206 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
207 for (size_t index = 0; index < requests.size(); index++) {
208 DCHECK(index < accept_state.size());
209 // The row is laid out containing a leading-aligned label area and a
210 // trailing column which will be filled if there are multiple permission
211 // requests.
212 views::View* row = new views::View();
213 views::GridLayout* row_layout = new views::GridLayout(row);
214 row->SetLayoutManager(row_layout);
215 views::ColumnSet* columns = row_layout->AddColumnSet(0);
216 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL,
217 0, views::GridLayout::USE_PREF, 0, 0);
218 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::FILL,
219 100, views::GridLayout::USE_PREF, 0, 0);
220 row_layout->StartRow(0, 0);
221
222 views::View* label_container = new views::View();
223 label_container->SetLayoutManager(new views::BoxLayout(
224 views::BoxLayout::kHorizontal, views::kCheckboxIndent, 0,
225 views::kItemLabelSpacing));
226 views::ImageView* icon = new views::ImageView();
227 gfx::VectorIconId vector_id = requests[index]->GetVectorIconId();
228 if (vector_id != gfx::VectorIconId::VECTOR_ICON_NONE) {
229 icon->SetImage(
230 gfx::CreateVectorIcon(vector_id, kIconSize, gfx::kChromeIconGrey));
231 } else {
232 icon->SetImage(bundle.GetImageSkiaNamed(requests.at(index)->GetIconId()));
233 icon->SetImageSize(gfx::Size(kIconSize, kIconSize));
234 }
235 icon->SetTooltipText(base::string16()); // Redundant with the text fragment
236 label_container->AddChildView(icon);
237 views::Label* label =
238 new views::Label(requests.at(index)->GetMessageTextFragment());
239 label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
240 label_container->AddChildView(label);
241 row_layout->AddView(label_container);
242
243 if (requests.size() > 1) {
244 PermissionCombobox* combobox = new PermissionCombobox(
245 this, index, requests[index]->GetOrigin(),
246 accept_state[index] ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK);
247 row_layout->AddView(combobox);
248 customize_comboboxes_.push_back(combobox);
249 } else {
250 row_layout->AddView(new views::View());
251 }
252
253 AddChildView(row);
254 }
255 }
256
257 PermissionsBubbleDialogDelegateView::~PermissionsBubbleDialogDelegateView() {
258 if (owner_)
259 owner_->Closing();
260 }
261
262 void PermissionsBubbleDialogDelegateView::CloseBubble() {
263 owner_ = nullptr;
264 GetWidget()->Close();
265 }
266
267 bool PermissionsBubbleDialogDelegateView::ShouldShowCloseButton() const {
268 return true;
269 }
270
271 const gfx::FontList& PermissionsBubbleDialogDelegateView::GetTitleFontList()
272 const {
273 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
274 return rb.GetFontList(ui::ResourceBundle::BaseFont);
275 }
276
277 base::string16 PermissionsBubbleDialogDelegateView::GetWindowTitle() const {
278 return l10n_util::GetStringFUTF16(IDS_PERMISSIONS_BUBBLE_PROMPT,
279 display_origin_);
280 }
281
282 void PermissionsBubbleDialogDelegateView::SizeToContents() {
283 BubbleDialogDelegateView::SizeToContents();
284 }
285
286 void PermissionsBubbleDialogDelegateView::OnWidgetDestroying(
287 views::Widget* widget) {
288 views::BubbleDialogDelegateView::OnWidgetDestroying(widget);
289 if (owner_) {
290 owner_->Closing();
291 owner_ = nullptr;
292 }
293 }
294
295 gfx::Size PermissionsBubbleDialogDelegateView::GetPreferredSize() const {
296 // TODO(estade): bubbles should default to this width.
297 const int kWidth = 320 - GetInsets().width();
298 return gfx::Size(kWidth, GetHeightForWidth(kWidth));
299 }
300
301 void PermissionsBubbleDialogDelegateView::GetAccessibleState(
302 ui::AXViewState* state) {
303 views::BubbleDialogDelegateView::GetAccessibleState(state);
304 state->role = ui::AX_ROLE_ALERT_DIALOG;
305 }
306
307 int PermissionsBubbleDialogDelegateView::GetDialogButtons() const {
308 int buttons = ui::DIALOG_BUTTON_OK;
309 if (!multiple_requests_)
310 buttons |= ui::DIALOG_BUTTON_CANCEL;
311 return buttons;
312 }
313
314 base::string16 PermissionsBubbleDialogDelegateView::GetDialogButtonLabel(
315 ui::DialogButton button) const {
316 if (button == ui::DIALOG_BUTTON_CANCEL)
317 return l10n_util::GetStringUTF16(IDS_PERMISSION_DENY);
318
319 // The text differs based on whether OK is the only visible button.
320 return l10n_util::GetStringUTF16(GetDialogButtons() == ui::DIALOG_BUTTON_OK
321 ? IDS_OK
322 : IDS_PERMISSION_ALLOW);
323 }
324
325 bool PermissionsBubbleDialogDelegateView::Cancel() {
326 if (owner_)
327 owner_->Deny();
328 return true;
329 }
330
331 bool PermissionsBubbleDialogDelegateView::Accept() {
332 if (owner_)
333 owner_->Accept();
334 return true;
335 }
336
337 bool PermissionsBubbleDialogDelegateView::Close() {
338 // Neither explicit accept nor explicit deny.
339 return true;
340 }
341
342 void PermissionsBubbleDialogDelegateView::PermissionSelectionChanged(
343 int index,
344 bool allowed) {
345 owner_->Toggle(index, allowed);
346 }
347
348 void PermissionsBubbleDialogDelegateView::UpdateAnchor(
349 views::View* anchor_view,
350 const gfx::Point& anchor_point,
351 views::BubbleBorder::Arrow anchor_arrow) {
352 set_arrow(anchor_arrow);
353
354 // Update the border in the bubble: will either add or remove the arrow.
355 views::BubbleFrameView* frame =
356 views::BubbleDialogDelegateView::GetBubbleFrameView();
357 views::BubbleBorder::Arrow adjusted_arrow = anchor_arrow;
358 if (base::i18n::IsRTL())
359 adjusted_arrow = views::BubbleBorder::horizontal_mirror(adjusted_arrow);
360 frame->SetBubbleBorder(std::unique_ptr<views::BubbleBorder>(
361 new views::BubbleBorder(adjusted_arrow, shadow(), color())));
362
363 // Reposition the bubble based on the updated arrow and view.
364 SetAnchorView(anchor_view);
365 // The anchor rect is ignored unless |anchor_view| is nullptr.
366 SetAnchorRect(gfx::Rect(anchor_point, gfx::Size()));
367 }
368
369 //////////////////////////////////////////////////////////////////////////////
370 // PermissionBubbleViewViews
371
372 PermissionBubbleViewViews::PermissionBubbleViewViews(Browser* browser)
373 : browser_(browser),
374 delegate_(nullptr),
375 bubble_delegate_(nullptr) {
376 DCHECK(browser);
377 DCHECK(browser->window());
378 }
379
380 PermissionBubbleViewViews::~PermissionBubbleViewViews() {
381 }
382
383 void PermissionBubbleViewViews::SetDelegate(Delegate* delegate) {
384 delegate_ = delegate;
385 }
386
387 void PermissionBubbleViewViews::Show(
388 const std::vector<PermissionRequest*>& requests,
389 const std::vector<bool>& values) {
390 if (bubble_delegate_)
391 bubble_delegate_->CloseBubble();
392
393 bubble_delegate_ = new PermissionsBubbleDialogDelegateView(
394 this, requests, values);
395
396 // Set |parent_window| because some valid anchors can become hidden.
397 bubble_delegate_->set_parent_window(
398 platform_util::GetViewForWindow(browser_->window()->GetNativeWindow()));
399
400 views::BubbleDialogDelegateView::CreateBubble(bubble_delegate_)->Show();
401 bubble_delegate_->SizeToContents();
402
403 bubble_delegate_->UpdateAnchor(GetAnchorView(),
404 GetAnchorPoint(),
405 GetAnchorArrow());
406 }
407
408 bool PermissionBubbleViewViews::CanAcceptRequestUpdate() {
409 return !(bubble_delegate_ && bubble_delegate_->IsMouseHovered());
410 }
411
412 void PermissionBubbleViewViews::Hide() {
413 if (bubble_delegate_) {
414 bubble_delegate_->CloseBubble();
415 bubble_delegate_ = nullptr;
416 }
417 }
418
419 bool PermissionBubbleViewViews::IsVisible() {
420 return bubble_delegate_ != nullptr;
421 }
422
423 void PermissionBubbleViewViews::UpdateAnchorPosition() {
424 if (IsVisible()) {
425 bubble_delegate_->set_parent_window(
426 platform_util::GetViewForWindow(browser_->window()->GetNativeWindow()));
427 bubble_delegate_->UpdateAnchor(GetAnchorView(),
428 GetAnchorPoint(),
429 GetAnchorArrow());
430 }
431 }
432
433 gfx::NativeWindow PermissionBubbleViewViews::GetNativeWindow() {
434 if (bubble_delegate_ && bubble_delegate_->GetWidget())
435 return bubble_delegate_->GetWidget()->GetNativeWindow();
436 return nullptr;
437 }
438
439 void PermissionBubbleViewViews::Closing() {
440 if (bubble_delegate_)
441 bubble_delegate_ = nullptr;
442 if (delegate_)
443 delegate_->Closing();
444 }
445
446 void PermissionBubbleViewViews::Toggle(int index, bool value) {
447 if (delegate_)
448 delegate_->ToggleAccept(index, value);
449 }
450
451 void PermissionBubbleViewViews::Accept() {
452 if (delegate_)
453 delegate_->Accept();
454 }
455
456 void PermissionBubbleViewViews::Deny() {
457 if (delegate_)
458 delegate_->Deny();
459 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698