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

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

Issue 1408193003: Add chrome side webusb permission UI code (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: call UsbChooserContext::GrantDevicePermission when user grants permission to a device Created 5 years, 1 month 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 2015 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/chooser_bubble_ui_view.h"
6
7 #include <string>
8
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/views/exclusive_access_bubble_views.h"
15 #include "chrome/browser/ui/views/frame/browser_view.h"
16 #include "chrome/browser/ui/views/frame/top_container_view.h"
17 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
18 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
19 #include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h"
20 #include "chrome/browser/ui/website_settings/chooser_choices.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/grit/generated_resources.h"
23 #include "ui/accessibility/ax_view_state.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/resource/resource_bundle.h"
26 #include "ui/gfx/paint_vector_icon.h"
27 #include "ui/gfx/text_constants.h"
28 #include "ui/gfx/vector_icons_public.h"
29 #include "ui/views/bubble/bubble_delegate.h"
30 #include "ui/views/bubble/bubble_frame_view.h"
31 #include "ui/views/controls/button/label_button.h"
32 #include "ui/views/controls/button/label_button_border.h"
33 #include "ui/views/controls/table/table_view.h"
34 #include "ui/views/controls/table/table_view_observer.h"
35 #include "ui/views/layout/box_layout.h"
36 #include "ui/views/layout/grid_layout.h"
37
38 namespace {
39
40 // chooser permission bubble width
41 const int kChooserPermissionBubbleWidth = 300;
42
43 // chooser permission bubble height
44 const int kChooserPermissionBubbleHeight = 200;
45
46 // Spacing constant for outer margin. This is added to the
47 // bubble margin itself to equalize the margins at 13px.
48 const int kBubbleOuterMargin = 5;
49
50 // Spacing between major items should be 9px.
51 const int kItemMajorSpacing = 9;
52
53 // Button border size, draws inside the spacing distance.
54 const int kButtonBorderSize = 2;
55
56 } // namespace
57
58 class ChooserTableModel;
59
60 ///////////////////////////////////////////////////////////////////////////////
61 // View implementation for the chooser bubble.
62 class ChooserBubbleUiViewDelegate : public views::BubbleDelegateView,
63 public views::ButtonListener,
64 public views::TableViewObserver {
65 public:
66 ChooserBubbleUiViewDelegate(views::View* anchor_view,
67 views::BubbleBorder::Arrow anchor_arrow,
68 ChooserBubbleUiView* owner,
69 ChooserChoices* chooser_choices,
70 ChooserBubbleDelegate* chooser_bubble_delegate);
71 ~ChooserBubbleUiViewDelegate() override;
72
73 void Close();
74
75 // BubbleDelegateView:
76 bool ShouldShowCloseButton() const override;
77 bool ShouldShowWindowTitle() const override;
78 base::string16 GetWindowTitle() const override;
79 void OnWidgetDestroying(views::Widget* widget) override;
80
81 // ButtonListener:
82 void ButtonPressed(views::Button* button, const ui::Event& event) override;
83
84 // views::TableViewObserver:
85 void OnSelectionChanged() override;
86
87 // Updates the anchor's arrow and view. Also repositions the bubble so it's
88 // displayed in the correct location.
89 void UpdateAnchor(views::View* anchor_view,
90 views::BubbleBorder::Arrow anchor_arrow);
91
92 private:
93 friend ChooserBubbleUiView;
94
95 ChooserBubbleUiView* owner_;
96 ChooserChoices* chooser_choices_;
97 ChooserBubbleDelegate* chooser_bubble_delegate_;
98
99 views::LabelButton* connect_button_;
100 views::LabelButton* cancel_button_;
101 views::TableView* table_view_;
102 ChooserTableModel* chooser_table_model_;
103
104 DISALLOW_COPY_AND_ASSIGN(ChooserBubbleUiViewDelegate);
105 };
106
107 ui::TableColumn ChooserTableColumn(int id, const std::string& title) {
108 ui::TableColumn column;
109 column.id = id;
110 column.title = base::ASCIIToUTF16(title.c_str());
111 return column;
112 }
113
114 class ChooserTableModel : public ui::TableModel,
115 public ChooserChoices::Observer {
116 public:
117 explicit ChooserTableModel(ChooserChoices* chooser_choices)
118 : observer_(nullptr), chooser_choices_(chooser_choices) {
119 chooser_choices_->set_observer(this);
120 }
121
122 // ui::TableModel:
123 int RowCount() override {
124 const std::vector<std::string>& device_names =
125 chooser_choices_->GetChoices();
126 if (device_names.empty()) {
127 return 1;
128 } else {
129 return static_cast<int>(chooser_choices_->GetChoices().size());
130 }
131 }
132
133 // ui::TableModel:
134 base::string16 GetText(int row, int column_id) override {
135 const std::vector<std::string>& device_names =
136 chooser_choices_->GetChoices();
137 if (device_names.empty()) {
138 DCHECK(row == 0);
139 return l10n_util::GetStringUTF16(
140 IDS_CHOOSER_BUBBLE_NO_DEVICES_FOUND_PROMPT);
141 } else {
142 if (row >= 0 && row < static_cast<int>(device_names.size())) {
143 return base::ASCIIToUTF16(device_names[row]);
144 } else {
145 return base::string16();
146 }
147 }
148 }
149
150 // ui::TableModel:
151 void SetObserver(ui::TableModelObserver* observer) override {
152 observer_ = observer;
153 }
154
155 // ChooserChoices::Observer:
156 void OnChoicesInitialized() override {
157 if (observer_) {
158 observer_->OnModelChanged();
159 Update();
160 }
161 }
162
163 // ChooserChoices::Observer:
164 void OnChoiceAdded(int index) override {
165 if (observer_) {
166 observer_->OnItemsAdded(index, 1);
167 Update();
168 }
169 }
170
171 // ChooserChoices::Observer:
172 void OnChoiceRemoved(int index) override {
173 if (observer_) {
174 observer_->OnItemsRemoved(index, 1);
175 Update();
176 }
177 }
178
179 void SetConnectButton(views::LabelButton* connect_button) {
180 connect_button_ = connect_button;
181 }
182
183 private:
184 void Update() {
185 views::TableView* table_view = static_cast<views::TableView*>(observer_);
186
187 if (chooser_choices_->GetChoices().empty()) {
188 observer_->OnModelChanged();
189 table_view->SetEnabled(false);
190 } else {
191 table_view->SetEnabled(true);
192 }
193
194 if (table_view->selection_model().empty() ||
195 chooser_choices_->GetChoices().empty())
196 connect_button_->SetEnabled(false);
197 }
198
199 ui::TableModelObserver* observer_ = nullptr;
200 ChooserChoices* chooser_choices_;
201 views::LabelButton* connect_button_;
202 };
203
204 ChooserBubbleUiViewDelegate::ChooserBubbleUiViewDelegate(
205 views::View* anchor_view,
206 views::BubbleBorder::Arrow anchor_arrow,
207 ChooserBubbleUiView* owner,
208 ChooserChoices* chooser_choices,
209 ChooserBubbleDelegate* chooser_bubble_delegate)
210 : views::BubbleDelegateView(anchor_view, anchor_arrow),
211 owner_(owner),
212 chooser_choices_(chooser_choices),
213 chooser_bubble_delegate_(chooser_bubble_delegate),
214 connect_button_(nullptr),
215 cancel_button_(nullptr) {
Reilly Grant (use Gerrit) 2015/11/12 21:44:36 No need to initialize these two fields since they
juncai 2015/11/14 01:54:36 Done.
216 views::GridLayout* layout = new views::GridLayout(this);
217 SetLayoutManager(layout);
218
219 views::ColumnSet* column_set = layout->AddColumnSet(0);
220 column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
221 views::GridLayout::USE_PREF, 0, 0);
222
223 layout->StartRow(1, 0);
224
225 // create a table view
226 std::vector<ui::TableColumn> table_columns;
227 table_columns.push_back(ChooserTableColumn(
228 0, "" /* empty string makes the column title invisible */));
229 chooser_table_model_ = new ChooserTableModel(chooser_choices_);
230 table_view_ = new views::TableView(chooser_table_model_, table_columns,
231 views::TEXT_ONLY, true);
232 table_view_->set_select_on_remove(false);
233 chooser_table_model_->SetObserver(table_view_);
234 table_view_->SetObserver(this);
235 layout->AddView(table_view_->CreateParentIfNecessary(), 1, 1,
236 views::GridLayout::FILL, views::GridLayout::FILL,
237 kChooserPermissionBubbleWidth,
238 kChooserPermissionBubbleHeight);
239 if (chooser_choices_->GetChoices().empty()) {
240 table_view_->SetEnabled(false);
241 }
242
243 layout->AddPaddingRow(0, kItemMajorSpacing);
244
245 views::View* button_row = new views::View();
246 views::GridLayout* button_layout = new views::GridLayout(button_row);
247 views::ColumnSet* button_columns = button_layout->AddColumnSet(0);
248 button_row->SetLayoutManager(button_layout);
249 layout->StartRow(1, 0);
250 layout->AddView(button_row);
251
252 // lay out the Connect/Cancel buttons.
253 button_columns->AddColumn(views::GridLayout::TRAILING,
254 views::GridLayout::FILL, 100,
255 views::GridLayout::USE_PREF, 0, 0);
256 button_columns->AddPaddingColumn(0,
257 kItemMajorSpacing - (2 * kButtonBorderSize));
258 button_columns->AddColumn(views::GridLayout::TRAILING,
259 views::GridLayout::FILL, 0,
260 views::GridLayout::USE_PREF, 0, 0);
261 button_layout->StartRow(0, 0);
262
263 base::string16 connect_text = base::ASCIIToUTF16("Connect");
Reilly Grant (use Gerrit) 2015/11/12 21:44:36 Add localizable strings for these button labels to
juncai 2015/11/14 01:54:36 Done.
264 connect_button_ = new views::LabelButton(this, connect_text);
265 connect_button_->SetStyle(views::Button::STYLE_BUTTON);
266 // disable the connect button at the beginning since no device selected yet.
267 connect_button_->SetEnabled(false);
268 button_layout->AddView(connect_button_);
269 chooser_table_model_->SetConnectButton(connect_button_);
270
271 base::string16 cancel_text = base::ASCIIToUTF16("Cancel");
272 cancel_button_ = new views::LabelButton(this, cancel_text);
273 cancel_button_->SetStyle(views::Button::STYLE_BUTTON);
274 button_layout->AddView(cancel_button_);
275
276 button_layout->AddPaddingRow(0, kBubbleOuterMargin);
277 }
278
279 ChooserBubbleUiViewDelegate::~ChooserBubbleUiViewDelegate() {
280 RemoveAllChildViews(true);
281 if (owner_)
282 owner_->Close();
283 chooser_table_model_->SetObserver(nullptr);
284 }
285
286 void ChooserBubbleUiViewDelegate::Close() {
287 owner_ = nullptr;
288 GetWidget()->Close();
289 }
290
291 bool ChooserBubbleUiViewDelegate::ShouldShowCloseButton() const {
292 return true;
293 }
294
295 bool ChooserBubbleUiViewDelegate::ShouldShowWindowTitle() const {
296 return true;
297 }
298
299 base::string16 ChooserBubbleUiViewDelegate::GetWindowTitle() const {
300 return l10n_util::GetStringUTF16(IDS_CHOOSER_BUBBLE_PROMPT);
301 }
302
303 void ChooserBubbleUiViewDelegate::OnWidgetDestroying(views::Widget* widget) {
304 views::BubbleDelegateView::OnWidgetDestroying(widget);
305 if (owner_) {
306 owner_->Close();
307 owner_ = nullptr;
308 }
309 }
310
311 void ChooserBubbleUiViewDelegate::ButtonPressed(views::Button* button,
312 const ui::Event& event) {
313 if (button == connect_button_)
314 chooser_bubble_delegate_->Select(table_view_->selection_model().active());
315 else if (button == cancel_button_)
316 chooser_bubble_delegate_->Cancel();
317 }
318
319 void ChooserBubbleUiViewDelegate::OnSelectionChanged() {
320 // enable the connect button since user has selected an item.
321 connect_button_->SetEnabled(true);
Reilly Grant (use Gerrit) 2015/11/12 21:44:36 Didn't we determine that OnSelectionChanged not be
juncai 2015/11/14 01:54:36 Done.
322 }
323
324 void ChooserBubbleUiViewDelegate::UpdateAnchor(
325 views::View* anchor_view,
326 views::BubbleBorder::Arrow anchor_arrow) {
327 if (GetAnchorView() == anchor_view && arrow() == anchor_arrow)
328 return;
329
330 set_arrow(anchor_arrow);
331
332 // Update the border in the bubble: will either add or remove the arrow.
333 views::BubbleFrameView* frame =
334 views::BubbleDelegateView::GetBubbleFrameView();
335 views::BubbleBorder::Arrow adjusted_arrow = anchor_arrow;
336 if (base::i18n::IsRTL())
337 adjusted_arrow = views::BubbleBorder::horizontal_mirror(adjusted_arrow);
338 frame->SetBubbleBorder(scoped_ptr<views::BubbleBorder>(
339 new views::BubbleBorder(adjusted_arrow, shadow(), color())));
340
341 // Reposition the bubble based on the updated arrow and view.
342 SetAnchorView(anchor_view);
343 }
344
345 //////////////////////////////////////////////////////////////////////////////
346 // ChooserBubbleUiView
347
348 ChooserBubbleUiView::ChooserBubbleUiView(
349 Browser* browser,
350 ChooserChoices* chooser_choices,
351 ChooserBubbleDelegate* chooser_bubble_delegate)
352 : browser_(browser),
353 chooser_choices_(chooser_choices),
354 chooser_bubble_delegate_(chooser_bubble_delegate),
355 chooser_bubble_ui_view_delegate_(nullptr) {
356 DCHECK(browser_);
357 DCHECK(chooser_choices_);
358 DCHECK(chooser_bubble_delegate_);
359 }
360
361 ChooserBubbleUiView::~ChooserBubbleUiView() {}
362
363 void ChooserBubbleUiView::Show(BubbleReference bubble_reference) {
364 chooser_bubble_ui_view_delegate_ = new ChooserBubbleUiViewDelegate(
365 GetAnchorView(), GetAnchorArrow(), this, chooser_choices_,
366 chooser_bubble_delegate_);
367
368 // Set |parent_window| because some valid anchors can become hidden.
369 views::Widget* widget = views::Widget::GetWidgetForNativeWindow(
370 browser_->window()->GetNativeWindow());
371 chooser_bubble_ui_view_delegate_->set_parent_window(widget->GetNativeView());
372
373 views::BubbleDelegateView::CreateBubble(chooser_bubble_ui_view_delegate_)
374 ->Show();
375 }
376
377 void ChooserBubbleUiView::Close() {
378 if (chooser_bubble_ui_view_delegate_) {
379 chooser_bubble_ui_view_delegate_->Close();
380 chooser_bubble_ui_view_delegate_ = nullptr;
381 }
382 }
383
384 void ChooserBubbleUiView::UpdateAnchorPosition() {
385 if (chooser_bubble_ui_view_delegate_) {
386 chooser_bubble_ui_view_delegate_->UpdateAnchor(GetAnchorView(),
387 GetAnchorArrow());
388 }
389 }
390
391 views::View* ChooserBubbleUiView::GetAnchorView() {
392 BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_);
393
394 if (browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR))
395 return browser_view->GetLocationBarView()->location_icon_view();
396
397 if (browser_view->IsFullscreenBubbleVisible())
398 return browser_view->exclusive_access_bubble()->GetView();
399
400 return browser_view->top_container();
401 }
402
403 views::BubbleBorder::Arrow ChooserBubbleUiView::GetAnchorArrow() {
404 if (browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR))
405 return views::BubbleBorder::TOP_LEFT;
406 return views::BubbleBorder::NONE;
407 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698