permission_selector_view.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
1// Copyright (c) 2012 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/permission_selector_view.h"
6
7#include "base/strings/utf_string_conversions.h"
8#include "chrome/browser/ui/website_settings/permission_menu_model.h"
9#include "chrome/browser/ui/website_settings/website_settings_ui.h"
10#include "grit/generated_resources.h"
11#include "ui/accessibility/ax_view_state.h"
12#include "ui/base/l10n/l10n_util.h"
13#include "ui/gfx/image/image.h"
14#include "ui/views/controls/button/menu_button.h"
15#include "ui/views/controls/image_view.h"
16#include "ui/views/controls/label.h"
17#include "ui/views/controls/menu/menu_runner.h"
18#include "ui/views/layout/grid_layout.h"
19#include "ui/views/view.h"
20#include "ui/views/widget/widget.h"
21
22namespace {
23
24// Left icon margin.
25const int kPermissionIconMarginLeft = 6;
26// The width of the column that contains the permissions icons.
27const int kPermissionIconColumnWidth = 20;
28
29}  // namespace
30
31namespace internal {
32
33// The |PermissionMenuButton| provides a menu for selecting a setting a
34// permissions type.
35class PermissionMenuButton : public views::MenuButton,
36                             public views::MenuButtonListener {
37 public:
38  // Creates a new |PermissionMenuButton| with the passed |text|. The ownership
39  // of the |model| remains with the caller and is not transfered to the
40  // |PermissionMenuButton|. If the |show_menu_marker| flag is true, then a
41  // small icon is be displayed next to the button |text|, indicating that the
42  // button opens a drop down menu.
43  PermissionMenuButton(const base::string16& text,
44                       PermissionMenuModel* model,
45                       bool show_menu_marker);
46  virtual ~PermissionMenuButton();
47
48  // Overridden from views::TextButton.
49  virtual void SetText(const base::string16& text) OVERRIDE;
50
51  // Overridden from views::View.
52  virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE;
53  virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE;
54
55 private:
56  // Overridden from views::MenuButtonListener.
57  virtual void OnMenuButtonClicked(View* source,
58                                   const gfx::Point& point) OVERRIDE;
59
60  PermissionMenuModel* menu_model_;  // Owned by |PermissionSelectorView|.
61  scoped_ptr<views::MenuRunner> menu_runner_;
62
63  DISALLOW_COPY_AND_ASSIGN(PermissionMenuButton);
64};
65
66///////////////////////////////////////////////////////////////////////////////
67// PermissionMenuButton
68///////////////////////////////////////////////////////////////////////////////
69
70PermissionMenuButton::PermissionMenuButton(const base::string16& text,
71                                           PermissionMenuModel* model,
72                                           bool show_menu_marker)
73    : MenuButton(NULL, text, this, show_menu_marker),
74      menu_model_(model) {
75}
76
77PermissionMenuButton::~PermissionMenuButton() {
78}
79
80void PermissionMenuButton::SetText(const base::string16& text) {
81  MenuButton::SetText(text);
82  SizeToPreferredSize();
83}
84
85void PermissionMenuButton::GetAccessibleState(ui::AXViewState* state) {
86  MenuButton::GetAccessibleState(state);
87  state->value = GetText();
88}
89
90void PermissionMenuButton::OnNativeThemeChanged(const ui::NativeTheme* theme) {
91  SetTextColor(views::Button::STATE_NORMAL, GetNativeTheme()->GetSystemColor(
92      ui::NativeTheme::kColorId_LabelEnabledColor));
93  SetTextColor(views::Button::STATE_HOVERED, GetNativeTheme()->GetSystemColor(
94      ui::NativeTheme::kColorId_LabelEnabledColor));
95  SetTextColor(views::Button::STATE_DISABLED, GetNativeTheme()->GetSystemColor(
96      ui::NativeTheme::kColorId_LabelDisabledColor));
97}
98
99void PermissionMenuButton::OnMenuButtonClicked(View* source,
100                                               const gfx::Point& point) {
101  menu_runner_.reset(new views::MenuRunner(menu_model_));
102
103  gfx::Point p(point);
104  p.Offset(-source->width(), 0);
105  if (menu_runner_->RunMenuAt(source->GetWidget()->GetTopLevelWidget(),
106                              this,
107                              gfx::Rect(p, gfx::Size()),
108                              views::MENU_ANCHOR_TOPLEFT,
109                              ui::MENU_SOURCE_NONE,
110                              views::MenuRunner::HAS_MNEMONICS) ==
111      views::MenuRunner::MENU_DELETED) {
112    return;
113  }
114}
115
116}  // namespace internal
117
118///////////////////////////////////////////////////////////////////////////////
119// PermissionSelectorView
120///////////////////////////////////////////////////////////////////////////////
121
122PermissionSelectorView::PermissionSelectorView(
123    const GURL& url,
124    const WebsiteSettingsUI::PermissionInfo& permission)
125    : icon_(NULL), menu_button_(NULL) {
126  views::GridLayout* layout = new views::GridLayout(this);
127  SetLayoutManager(layout);
128  const int column_set_id = 0;
129  views::ColumnSet* column_set = layout->AddColumnSet(column_set_id);
130  column_set->AddColumn(views::GridLayout::FILL,
131                        views::GridLayout::FILL,
132                        1,
133                        views::GridLayout::FIXED,
134                        kPermissionIconColumnWidth,
135                        0);
136  column_set->AddPaddingColumn(0, kPermissionIconMarginLeft);
137  column_set->AddColumn(views::GridLayout::FILL,
138                        views::GridLayout::FILL,
139                        1,
140                        views::GridLayout::USE_PREF,
141                        0,
142                        0);
143  column_set->AddColumn(views::GridLayout::FILL,
144                        views::GridLayout::FILL,
145                        1,
146                        views::GridLayout::USE_PREF,
147                        0,
148                        0);
149
150  layout->StartRow(1, column_set_id);
151  // Create the permission icon.
152  icon_ = new views::ImageView();
153  const gfx::Image& image = WebsiteSettingsUI::GetPermissionIcon(permission);
154  icon_->SetImage(image.ToImageSkia());
155  layout->AddView(icon_,
156                  1,
157                  1,
158                  views::GridLayout::CENTER,
159                  views::GridLayout::CENTER);
160  // Create the label that displays the permission type.
161  views::Label* label = new views::Label(l10n_util::GetStringFUTF16(
162      IDS_WEBSITE_SETTINGS_PERMISSION_TYPE,
163      WebsiteSettingsUI::PermissionTypeToUIString(permission.type)));
164  layout->AddView(label,
165                  1,
166                  1,
167                  views::GridLayout::LEADING,
168                  views::GridLayout::CENTER);
169  // Create the menu model.
170  menu_model_.reset(new PermissionMenuModel(
171      url,
172      permission,
173      base::Bind(&PermissionSelectorView::PermissionChanged,
174                 base::Unretained(this))));
175  // Create the permission menu button.
176  bool button_enabled =
177      permission.source == content_settings::SETTING_SOURCE_USER;
178  menu_button_ = new internal::PermissionMenuButton(
179      WebsiteSettingsUI::PermissionActionToUIString(
180          permission.setting, permission.default_setting, permission.source),
181      menu_model_.get(),
182      button_enabled);
183  menu_button_->SetEnabled(button_enabled);
184  menu_button_->SetFocusable(button_enabled);
185  menu_button_->SetAccessibleName(
186      WebsiteSettingsUI::PermissionTypeToUIString(permission.type));
187  layout->AddView(menu_button_);
188}
189
190void PermissionSelectorView::AddObserver(
191    PermissionSelectorViewObserver* observer) {
192  observer_list_.AddObserver(observer);
193}
194
195void PermissionSelectorView::ChildPreferredSizeChanged(View* child) {
196  SizeToPreferredSize();
197  // FIXME: The parent is only a plain |View| that is used as a
198  // container/box/panel. The SizeToPreferredSize method of the parent is
199  // called here directly in order not to implement a custom |View| class with
200  // its own implementation of the ChildPreferredSizeChanged method.
201  parent()->SizeToPreferredSize();
202}
203
204PermissionSelectorView::~PermissionSelectorView() {
205}
206
207void PermissionSelectorView::PermissionChanged(
208    const WebsiteSettingsUI::PermissionInfo& permission) {
209  // Change the permission icon to reflect the selected setting.
210  const gfx::Image& image = WebsiteSettingsUI::GetPermissionIcon(permission);
211  icon_->SetImage(image.ToImageSkia());
212
213  // Update the menu button text to reflect the new setting.
214  menu_button_->SetText(WebsiteSettingsUI::PermissionActionToUIString(
215      permission.setting,
216      permission.default_setting,
217      content_settings::SETTING_SOURCE_USER));
218
219  FOR_EACH_OBSERVER(PermissionSelectorViewObserver,
220                    observer_list_,
221                    OnPermissionChanged(permission));
222}
223