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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc
diff --git a/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc b/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc
new file mode 100644
index 0000000000000000000000000000000000000000..15851bf48633194dcca349dd2d234725cfda7a3b
--- /dev/null
+++ b/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc
@@ -0,0 +1,406 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.h"
+
+#include <string>
+
+#include "base/prefs/pref_service.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/views/exclusive_access_bubble_views.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/frame/top_container_view.h"
+#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
+#include "chrome/browser/ui/views/location_bar/location_icon_view.h"
+#include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/accessibility/ax_view_state.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/gfx/text_constants.h"
+#include "ui/gfx/vector_icons_public.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/bubble/bubble_frame_view.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/label_button_border.h"
+#include "ui/views/controls/table/table_view.h"
+#include "ui/views/controls/table/table_view_observer.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/grid_layout.h"
+
+namespace {
+
+// Chooser permission bubble width
+const int kChooserPermissionBubbleWidth = 300;
+
+// Chooser permission bubble height
+const int kChooserPermissionBubbleHeight = 200;
+
+// Spacing constant for outer margin. This is added to the
+// bubble margin itself to equalize the margins at 13px.
+const int kBubbleOuterMargin = 5;
+
+// Spacing between major items should be 9px.
+const int kItemMajorSpacing = 9;
+
+// Button border size, draws inside the spacing distance.
+const int kButtonBorderSize = 2;
+
+} // namespace
+
+scoped_ptr<BubbleUi> ChooserBubbleDelegate::BuildBubbleUi() {
+ return make_scoped_ptr(new ChooserBubbleUiView(browser_, this));
+}
+
+class ChooserTableModel;
+
+///////////////////////////////////////////////////////////////////////////////
+// View implementation for the chooser bubble.
+class ChooserBubbleUiViewDelegate : public views::BubbleDelegateView,
+ public views::ButtonListener,
+ public views::TableViewObserver {
+ public:
+ ChooserBubbleUiViewDelegate(views::View* anchor_view,
+ views::BubbleBorder::Arrow anchor_arrow,
+ ChooserBubbleUiView* owner,
+ ChooserBubbleDelegate* chooser_bubble_delegate);
+ ~ChooserBubbleUiViewDelegate() override;
+
+ void Close();
+
+ // BubbleDelegateView:
+ bool ShouldShowCloseButton() const override;
+ bool ShouldShowWindowTitle() const override;
+ base::string16 GetWindowTitle() const override;
+ void OnWidgetDestroying(views::Widget* widget) override;
+
+ // ButtonListener:
+ void ButtonPressed(views::Button* button, const ui::Event& event) override;
+
+ // views::TableViewObserver:
+ void OnSelectionChanged() override;
+
+ // Updates the anchor's arrow and view. Also repositions the bubble so it's
+ // displayed in the correct location.
+ void UpdateAnchor(views::View* anchor_view,
+ views::BubbleBorder::Arrow anchor_arrow);
+
+ private:
+ friend ChooserBubbleUiView;
+
+ ChooserBubbleUiView* owner_;
+ ChooserBubbleDelegate* chooser_bubble_delegate_;
+
+ views::LabelButton* connect_button_;
+ views::LabelButton* cancel_button_;
+ views::TableView* table_view_;
+ ChooserTableModel* chooser_table_model_;
+ bool button_pressed_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChooserBubbleUiViewDelegate);
+};
+
+ui::TableColumn ChooserTableColumn(int id, const std::string& title) {
+ ui::TableColumn column;
+ column.id = id;
+ column.title = base::ASCIIToUTF16(title.c_str());
+ return column;
+}
+
+class ChooserTableModel : public ui::TableModel,
+ public ChooserBubbleDelegate::Observer {
+ public:
+ explicit ChooserTableModel(ChooserBubbleDelegate* chooser_bubble_delegate)
+ : observer_(nullptr), chooser_bubble_delegate_(chooser_bubble_delegate) {
+ chooser_bubble_delegate_->set_observer(this);
+ }
+
+ // ui::TableModel:
+ int RowCount() override {
+ const std::vector<base::string16>& device_names =
+ chooser_bubble_delegate_->GetOptions();
+ if (device_names.empty()) {
+ // Here it returns 1 when there is no device. In this case, the
+ // table view still needs to display a text message saying no
+ // devices found, so the number of rows is 1.
+ return 1;
+ } else {
+ return static_cast<int>(device_names.size());
+ }
+ }
+
+ // ui::TableModel:
+ base::string16 GetText(int row, int column_id) override {
+ const std::vector<base::string16>& device_names =
+ chooser_bubble_delegate_->GetOptions();
+ if (device_names.empty()) {
+ DCHECK(row == 0);
+ return l10n_util::GetStringUTF16(
+ IDS_CHOOSER_BUBBLE_NO_DEVICES_FOUND_PROMPT);
+ } else if (row >= 0 && row < static_cast<int>(device_names.size())) {
+ return device_names[row];
+ } else {
+ NOTREACHED();
+ return base::string16();
+ }
+ }
+
+ // ui::TableModel:
+ void SetObserver(ui::TableModelObserver* observer) override {
+ observer_ = observer;
+ }
+
+ // ChooserOptions::Observer:
+ void OnOptionsInitialized() override {
+ if (observer_) {
+ observer_->OnModelChanged();
+ Update();
+ }
+ }
+
+ // ChooserOptions::Observer:
+ void OnOptionAdded(int index) override {
+ if (observer_) {
+ observer_->OnItemsAdded(index, 1);
+ Update();
+ }
+ }
+
+ // ChooserOptions::Observer:
+ void OnOptionRemoved(int index) override {
+ if (observer_) {
+ observer_->OnItemsRemoved(index, 1);
+ Update();
+ }
+ }
+
+ void Update() {
+ views::TableView* table_view = static_cast<views::TableView*>(observer_);
+
+ if (chooser_bubble_delegate_->GetOptions().empty()) {
+ observer_->OnModelChanged();
+ table_view->SetEnabled(false);
+ } else {
+ table_view->SetEnabled(true);
+ }
+ }
+
+ void SetConnectButton(views::LabelButton* connect_button) {
+ connect_button_ = connect_button;
+ }
+
+ private:
+ ui::TableModelObserver* observer_;
+ ChooserBubbleDelegate* chooser_bubble_delegate_;
+ views::LabelButton* connect_button_;
+};
+
+ChooserBubbleUiViewDelegate::ChooserBubbleUiViewDelegate(
+ views::View* anchor_view,
+ views::BubbleBorder::Arrow anchor_arrow,
+ ChooserBubbleUiView* owner,
+ ChooserBubbleDelegate* chooser_bubble_delegate)
+ : views::BubbleDelegateView(anchor_view, anchor_arrow),
+ owner_(owner),
+ chooser_bubble_delegate_(chooser_bubble_delegate),
+ button_pressed_(false) {
+ views::GridLayout* layout = new views::GridLayout(this);
+ SetLayoutManager(layout);
+
+ views::ColumnSet* column_set = layout->AddColumnSet(0);
+ column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
+ views::GridLayout::USE_PREF, 0, 0);
+
+ layout->StartRow(1, 0);
+
+ // Create a table view
+ std::vector<ui::TableColumn> table_columns;
+ table_columns.push_back(ChooserTableColumn(
+ 0, "" /* Empty string makes the column title invisible */));
+ chooser_table_model_ = new ChooserTableModel(chooser_bubble_delegate_);
+ table_view_ = new views::TableView(chooser_table_model_, table_columns,
+ views::TEXT_ONLY, true);
+ table_view_->set_select_on_remove(false);
+ chooser_table_model_->SetObserver(table_view_);
+ table_view_->SetObserver(this);
+ layout->AddView(table_view_->CreateParentIfNecessary(), 1, 1,
+ views::GridLayout::FILL, views::GridLayout::FILL,
+ kChooserPermissionBubbleWidth,
+ kChooserPermissionBubbleHeight);
+ if (chooser_bubble_delegate_->GetOptions().empty()) {
+ table_view_->SetEnabled(false);
+ }
+
+ layout->AddPaddingRow(0, kItemMajorSpacing);
+
+ views::View* button_row = new views::View();
+ views::GridLayout* button_layout = new views::GridLayout(button_row);
+ views::ColumnSet* button_columns = button_layout->AddColumnSet(0);
+ button_row->SetLayoutManager(button_layout);
+ layout->StartRow(1, 0);
+ layout->AddView(button_row);
+
+ // Lay out the Connect/Cancel buttons.
+ button_columns->AddColumn(views::GridLayout::TRAILING,
+ views::GridLayout::FILL, 100,
+ views::GridLayout::USE_PREF, 0, 0);
+ button_columns->AddPaddingColumn(0,
+ kItemMajorSpacing - (2 * kButtonBorderSize));
+ button_columns->AddColumn(views::GridLayout::TRAILING,
+ views::GridLayout::FILL, 0,
+ views::GridLayout::USE_PREF, 0, 0);
+ button_layout->StartRow(0, 0);
+
+ base::string16 connect_text =
+ l10n_util::GetStringUTF16(IDS_CHOOSER_BUBBLE_CONNECT_BUTTON_TEXT);
+ connect_button_ = new views::LabelButton(this, connect_text);
+ connect_button_->SetStyle(views::Button::STYLE_BUTTON);
+ // Disable the connect button at the beginning since no device selected yet.
+ connect_button_->SetEnabled(false);
+ button_layout->AddView(connect_button_);
+ chooser_table_model_->SetConnectButton(connect_button_);
+
+ base::string16 cancel_text =
+ l10n_util::GetStringUTF16(IDS_CHOOSER_BUBBLE_CANCEL_BUTTON_TEXT);
+ cancel_button_ = new views::LabelButton(this, cancel_text);
+ cancel_button_->SetStyle(views::Button::STYLE_BUTTON);
+ button_layout->AddView(cancel_button_);
+
+ button_layout->AddPaddingRow(0, kBubbleOuterMargin);
+}
+
+ChooserBubbleUiViewDelegate::~ChooserBubbleUiViewDelegate() {
+ RemoveAllChildViews(true);
+ if (owner_)
+ owner_->Close();
+ chooser_table_model_->SetObserver(nullptr);
+}
+
+void ChooserBubbleUiViewDelegate::Close() {
+ if (!button_pressed_)
+ chooser_bubble_delegate_->Close();
+ owner_ = nullptr;
+ GetWidget()->Close();
+}
+
+bool ChooserBubbleUiViewDelegate::ShouldShowCloseButton() const {
+ return true;
+}
+
+bool ChooserBubbleUiViewDelegate::ShouldShowWindowTitle() const {
+ return true;
+}
+
+base::string16 ChooserBubbleUiViewDelegate::GetWindowTitle() const {
+ return l10n_util::GetStringUTF16(IDS_CHOOSER_BUBBLE_PROMPT);
+}
+
+void ChooserBubbleUiViewDelegate::OnWidgetDestroying(views::Widget* widget) {
+ views::BubbleDelegateView::OnWidgetDestroying(widget);
+ if (owner_) {
+ owner_->Close();
+ owner_ = nullptr;
+ }
+}
+
+void ChooserBubbleUiViewDelegate::ButtonPressed(views::Button* button,
+ const ui::Event& event) {
+ if (button == connect_button_)
+ chooser_bubble_delegate_->Select(table_view_->selection_model().active());
+ else
+ chooser_bubble_delegate_->Cancel();
+ button_pressed_ = true;
+ owner_->Close();
+}
+
+void ChooserBubbleUiViewDelegate::OnSelectionChanged() {
+ connect_button_->SetEnabled(!table_view_->selection_model().empty());
+}
+
+void ChooserBubbleUiViewDelegate::UpdateAnchor(
+ views::View* anchor_view,
+ views::BubbleBorder::Arrow anchor_arrow) {
+ if (GetAnchorView() == anchor_view && arrow() == anchor_arrow)
+ return;
+
+ set_arrow(anchor_arrow);
+
+ // Update the border in the bubble: will either add or remove the arrow.
+ views::BubbleFrameView* frame =
+ views::BubbleDelegateView::GetBubbleFrameView();
+ views::BubbleBorder::Arrow adjusted_arrow = anchor_arrow;
+ if (base::i18n::IsRTL())
+ adjusted_arrow = views::BubbleBorder::horizontal_mirror(adjusted_arrow);
+ frame->SetBubbleBorder(scoped_ptr<views::BubbleBorder>(
+ new views::BubbleBorder(adjusted_arrow, shadow(), color())));
+
+ // Reposition the bubble based on the updated arrow and view.
+ SetAnchorView(anchor_view);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// ChooserBubbleUiView
+
+ChooserBubbleUiView::ChooserBubbleUiView(
+ Browser* browser,
+ ChooserBubbleDelegate* chooser_bubble_delegate)
+ : browser_(browser),
+ chooser_bubble_delegate_(chooser_bubble_delegate),
+ chooser_bubble_ui_view_delegate_(nullptr) {
+ DCHECK(browser_);
+ DCHECK(chooser_bubble_delegate_);
+}
+
+ChooserBubbleUiView::~ChooserBubbleUiView() {}
+
+void ChooserBubbleUiView::Show(BubbleReference bubble_reference) {
+ chooser_bubble_ui_view_delegate_ = new ChooserBubbleUiViewDelegate(
+ GetAnchorView(), GetAnchorArrow(), this, chooser_bubble_delegate_);
+
+ // Set |parent_window| because some valid anchors can become hidden.
+ views::Widget* widget = views::Widget::GetWidgetForNativeWindow(
+ browser_->window()->GetNativeWindow());
+ chooser_bubble_ui_view_delegate_->set_parent_window(widget->GetNativeView());
+
+ views::BubbleDelegateView::CreateBubble(chooser_bubble_ui_view_delegate_)
+ ->Show();
+
+ chooser_bubble_ui_view_delegate_->chooser_table_model_->Update();
+}
+
+void ChooserBubbleUiView::Close() {
+ if (chooser_bubble_ui_view_delegate_) {
+ chooser_bubble_ui_view_delegate_->Close();
+ chooser_bubble_ui_view_delegate_ = nullptr;
+ }
+}
+
+void ChooserBubbleUiView::UpdateAnchorPosition() {
+ if (chooser_bubble_ui_view_delegate_) {
+ chooser_bubble_ui_view_delegate_->UpdateAnchor(GetAnchorView(),
+ GetAnchorArrow());
+ }
+}
+
+views::View* ChooserBubbleUiView::GetAnchorView() {
+ BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_);
+
+ if (browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR))
+ return browser_view->GetLocationBarView()->location_icon_view();
+
+ if (browser_view->IsFullscreenBubbleVisible())
+ return browser_view->exclusive_access_bubble()->GetView();
+
+ return browser_view->top_container();
+}
+
+views::BubbleBorder::Arrow ChooserBubbleUiView::GetAnchorArrow() {
+ if (browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR))
+ return views::BubbleBorder::TOP_LEFT;
+ return views::BubbleBorder::NONE;
+}

Powered by Google App Engine
This is Rietveld 408576698