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

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

Powered by Google App Engine
This is Rietveld 408576698