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/gtk/website_settings/permission_selector.h"
6
7#include "base/compiler_specific.h"
8#include "base/i18n/rtl.h"
9#include "base/strings/utf_string_conversions.h"
10#include "chrome/browser/ui/gtk/gtk_theme_service.h"
11#include "chrome/browser/ui/gtk/gtk_util.h"
12#include "chrome/browser/ui/gtk/menu_gtk.h"
13#include "chrome/browser/ui/website_settings/website_settings_ui.h"
14#include "grit/generated_resources.h"
15#include "grit/theme_resources.h"
16#include "ui/base/gtk/gtk_hig_constants.h"
17#include "ui/base/l10n/l10n_util.h"
18#include "ui/base/models/menu_model.h"
19#include "ui/base/resource/resource_bundle.h"
20#include "ui/gfx/image/image.h"
21
22namespace {
23
24ContentSetting CommandIdToContentSetting(int command_id) {
25  switch (command_id) {
26    case PermissionMenuModel::COMMAND_SET_TO_DEFAULT:
27      return CONTENT_SETTING_DEFAULT;
28    case PermissionMenuModel::COMMAND_SET_TO_ALLOW:
29      return CONTENT_SETTING_ALLOW;
30    case PermissionMenuModel::COMMAND_SET_TO_BLOCK:
31      return CONTENT_SETTING_BLOCK;
32    default:
33      NOTREACHED();
34      return CONTENT_SETTING_DEFAULT;
35  }
36}
37
38}  // namespace
39
40PermissionSelector::PermissionSelector(GtkThemeService* theme_service,
41                                       const GURL& url,
42                                       ContentSettingsType type,
43                                       ContentSetting setting,
44                                       ContentSetting default_setting,
45                                       content_settings::SettingSource source)
46    : widget_(NULL),
47      menu_button_(NULL),
48      icon_(NULL),
49      type_(type),
50      default_setting_(default_setting),
51      setting_(setting) {
52  DCHECK_NE(default_setting, CONTENT_SETTING_DEFAULT);
53
54  // Create permission info box.
55  const int kChildSpacing = 4;
56  widget_ = gtk_hbox_new(FALSE, kChildSpacing);
57
58  // Add permission type icon.
59  ContentSetting effective_setting = setting;
60  if (effective_setting == CONTENT_SETTING_DEFAULT)
61    effective_setting = default_setting;
62  GdkPixbuf* pixbuf = WebsiteSettingsUI::GetPermissionIcon(
63      type, effective_setting).ToGdkPixbuf();
64  icon_ = gtk_image_new_from_pixbuf(pixbuf);
65  gtk_box_pack_start(GTK_BOX(widget_), icon_, FALSE, FALSE, 0);
66
67  // Add a label for the permission type.
68  GtkWidget* label = theme_service->BuildLabel(l10n_util::GetStringFUTF8(
69      IDS_WEBSITE_SETTINGS_PERMISSION_TYPE,
70      WebsiteSettingsUI::PermissionTypeToUIString(type)),
71      ui::kGdkBlack);
72  gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR);
73
74  gtk_box_pack_start(GTK_BOX(widget_), label, FALSE, FALSE, 0);
75
76  // Add the menu button.
77  menu_button_ = theme_service->BuildChromeButton();
78  GtkWidget* button_hbox = gtk_hbox_new(FALSE, 0);
79  gtk_container_add(GTK_CONTAINER(menu_button_), button_hbox);
80
81  GtkWidget* button_label = theme_service->BuildLabel(
82      UTF16ToUTF8(WebsiteSettingsUI::PermissionActionToUIString(
83          setting, default_setting, source)),
84      ui::kGdkBlack);
85  gtk_box_pack_start(GTK_BOX(button_hbox), button_label, FALSE, FALSE,
86                     ui::kControlSpacing);
87
88  bool user_setting = source == content_settings::SETTING_SOURCE_USER;
89  gtk_widget_set_sensitive(GTK_WIDGET(menu_button_), user_setting);
90  if (user_setting) {
91    GtkWidget* arrow = NULL;
92    // We don't handle theme changes, which is a bug but they are very unlikely
93    // to occur while a bubble is grabbing input.
94    if (theme_service->UsingNativeTheme()) {
95      arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
96    } else {
97      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
98      arrow = gtk_image_new_from_pixbuf(
99          rb.GetNativeImageNamed(IDR_APP_DROPARROW).ToGdkPixbuf());
100    }
101    gtk_box_pack_start(GTK_BOX(button_hbox), arrow, FALSE, FALSE, 0);
102  }
103  gtk_button_set_relief(GTK_BUTTON(menu_button_), GTK_RELIEF_NONE);
104  gtk_box_pack_start(GTK_BOX(widget_), menu_button_, FALSE, FALSE, 0);
105
106  menu_model_.reset(new PermissionMenuModel(this, url, type, default_setting,
107                                            setting));
108  MenuGtk::Delegate* delegate = new MenuGtk::Delegate();
109  menu_.reset(new MenuGtk(delegate, menu_model_.get()));
110  g_signal_connect(menu_button_, "button-press-event",
111                   G_CALLBACK(OnMenuButtonPressEventThunk), this);
112}
113
114PermissionSelector::~PermissionSelector() {
115}
116
117void PermissionSelector::AddObserver(PermissionSelectorObserver* observer) {
118  observer_list_.AddObserver(observer);
119}
120
121ContentSetting PermissionSelector::GetSetting() const {
122  return setting_;
123}
124
125ContentSettingsType PermissionSelector::GetType() const {
126  return type_;
127}
128
129gboolean PermissionSelector::OnMenuButtonPressEvent(GtkWidget* button,
130                                                    GdkEventButton* event) {
131  if (event->button != 1)
132    return FALSE;
133  menu_->PopupForWidget(button, event->button, event->time);
134  return TRUE;
135}
136
137void PermissionSelector::ExecuteCommand(int command_id) {
138  setting_ = CommandIdToContentSetting(command_id);
139
140  // Change the permission icon to reflect the selected setting.
141  ContentSetting effective_setting = setting_;
142  if (effective_setting == CONTENT_SETTING_DEFAULT)
143    effective_setting = default_setting_;
144  GdkPixbuf* pixbuf = WebsiteSettingsUI::GetPermissionIcon(
145      type_, effective_setting).ToGdkPixbuf();
146  gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), pixbuf);
147
148  // Change the text of the menu button to reflect the selected setting.
149  gtk_button_set_label(GTK_BUTTON(menu_button_), UTF16ToUTF8(
150      WebsiteSettingsUI::PermissionActionToUIString(
151          setting_,
152          default_setting_,
153          content_settings::SETTING_SOURCE_USER)).c_str());
154
155  FOR_EACH_OBSERVER(PermissionSelectorObserver,
156                    observer_list_,
157                    OnPermissionChanged(this));
158}
159
160bool PermissionSelector::IsCommandIdChecked(int command_id) {
161  return setting_ == CommandIdToContentSetting(command_id);
162}
163