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

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

Powered by Google App Engine
This is Rietveld 408576698