1 // Copyright (c) 2011 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/notifications/notification_options_menu_model.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/logging.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/notifications/balloon_collection.h"
13 #include "chrome/browser/notifications/desktop_notification_service.h"
14 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
15 #include "chrome/browser/notifications/notification.h"
16 #include "chrome/browser/notifications/notification_ui_manager.h"
17 #include "chrome/browser/notifications/notifications_prefs_cache.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/ui/browser_list.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/content_settings_types.h"
22 #include "chrome/common/extensions/extension.h"
23 #include "chrome/common/url_constants.h"
24 #include "content/browser/tab_contents/tab_contents_delegate.h"
25 #include "grit/generated_resources.h"
26 #include "ui/base/l10n/l10n_util.h"
27
28 // Menu commands
29 const int kTogglePermissionCommand = 0;
30 const int kToggleExtensionCommand = 1;
31 const int kOpenContentSettingsCommand = 2;
32 const int kCornerSelectionSubMenu = 3;
33
34 const int kCornerGroupId = 10;
35 const int kCornerUpperLeft = 11;
36 const int kCornerUpperRight = 12;
37 const int kCornerLowerLeft = 13;
38 const int kCornerLowerRight = 14;
39 const int kCornerDefault = 20;
40
CornerSelectionMenuModel(Balloon * balloon)41 CornerSelectionMenuModel::CornerSelectionMenuModel(Balloon* balloon)
42 : ALLOW_THIS_IN_INITIALIZER_LIST(ui::SimpleMenuModel(this)),
43 balloon_(balloon) {
44 AddRadioItem(kCornerDefault,
45 l10n_util::GetStringUTF16(IDS_NOTIFICATION_POSITION_DEFAULT),
46 kCornerGroupId);
47 AddSeparator();
48 AddRadioItem(kCornerUpperLeft,
49 l10n_util::GetStringUTF16(IDS_NOTIFICATION_POSITION_UPPER_LEFT),
50 kCornerGroupId);
51 AddRadioItem(kCornerUpperRight,
52 l10n_util::GetStringUTF16(IDS_NOTIFICATION_POSITION_UPPER_RIGHT),
53 kCornerGroupId);
54 AddRadioItem(kCornerLowerLeft,
55 l10n_util::GetStringUTF16(IDS_NOTIFICATION_POSITION_LOWER_LEFT),
56 kCornerGroupId);
57 AddRadioItem(kCornerLowerRight,
58 l10n_util::GetStringUTF16(IDS_NOTIFICATION_POSITION_LOWER_RIGHT),
59 kCornerGroupId);
60 }
61
~CornerSelectionMenuModel()62 CornerSelectionMenuModel::~CornerSelectionMenuModel() {
63 }
64
IsCommandIdChecked(int command_id) const65 bool CornerSelectionMenuModel::IsCommandIdChecked(int command_id) const {
66 NotificationUIManager* ui = g_browser_process->notification_ui_manager();
67 BalloonCollection::PositionPreference current = ui->GetPositionPreference();
68
69 if (command_id == kCornerUpperLeft)
70 return (current == BalloonCollection::UPPER_LEFT);
71 else if (command_id == kCornerUpperRight)
72 return (current == BalloonCollection::UPPER_RIGHT);
73 else if (command_id == kCornerLowerLeft)
74 return (current == BalloonCollection::LOWER_LEFT);
75 else if (command_id == kCornerLowerRight)
76 return (current == BalloonCollection::LOWER_RIGHT);
77 else if (command_id == kCornerDefault)
78 return (current == BalloonCollection::DEFAULT_POSITION);
79
80 NOTREACHED();
81 return false;
82 }
83
IsCommandIdEnabled(int command_id) const84 bool CornerSelectionMenuModel::IsCommandIdEnabled(int command_id) const {
85 // All the menu options are always enabled.
86 return true;
87 }
88
GetAcceleratorForCommandId(int command_id,ui::Accelerator * accelerator)89 bool CornerSelectionMenuModel::GetAcceleratorForCommandId(
90 int command_id, ui::Accelerator* accelerator) {
91 // Currently no accelerators.
92 return false;
93 }
94
ExecuteCommand(int command_id)95 void CornerSelectionMenuModel::ExecuteCommand(int command_id) {
96 NotificationUIManager* ui = g_browser_process->notification_ui_manager();
97
98 if (command_id == kCornerUpperLeft)
99 ui->SetPositionPreference(BalloonCollection::UPPER_LEFT);
100 else if (command_id == kCornerUpperRight)
101 ui->SetPositionPreference(BalloonCollection::UPPER_RIGHT);
102 else if (command_id == kCornerLowerLeft)
103 ui->SetPositionPreference(BalloonCollection::LOWER_LEFT);
104 else if (command_id == kCornerLowerRight)
105 ui->SetPositionPreference(BalloonCollection::LOWER_RIGHT);
106 else if (command_id == kCornerDefault)
107 ui->SetPositionPreference(BalloonCollection::DEFAULT_POSITION);
108 else
109 NOTREACHED();
110 }
111
NotificationOptionsMenuModel(Balloon * balloon)112 NotificationOptionsMenuModel::NotificationOptionsMenuModel(Balloon* balloon)
113 : ALLOW_THIS_IN_INITIALIZER_LIST(ui::SimpleMenuModel(this)),
114 balloon_(balloon) {
115 const Notification& notification = balloon->notification();
116 const GURL& origin = notification.origin_url();
117
118 if (origin.SchemeIs(chrome::kExtensionScheme)) {
119 ExtensionService* ext_service =
120 balloon_->profile()->GetExtensionService();
121 const Extension* extension = ext_service->GetExtensionByURL(origin);
122 // We get back no extension here when we show the notification after
123 // the extension has crashed.
124 if (extension) {
125 const string16 disable_label = l10n_util::GetStringUTF16(
126 IDS_EXTENSIONS_DISABLE);
127 AddItem(kToggleExtensionCommand, disable_label);
128 }
129 } else {
130 const string16 disable_label = l10n_util::GetStringFUTF16(
131 IDS_NOTIFICATION_BALLOON_REVOKE_MESSAGE,
132 notification.display_source());
133 AddItem(kTogglePermissionCommand, disable_label);
134 }
135
136 const string16 settings_label = l10n_util::GetStringUTF16(
137 IDS_NOTIFICATIONS_SETTINGS_BUTTON);
138 AddItem(kOpenContentSettingsCommand, settings_label);
139
140 corner_menu_model_.reset(new CornerSelectionMenuModel(balloon));
141 AddSubMenu(kCornerSelectionSubMenu,
142 l10n_util::GetStringUTF16(IDS_NOTIFICATION_CHOOSE_POSITION),
143 corner_menu_model_.get());
144 }
145
~NotificationOptionsMenuModel()146 NotificationOptionsMenuModel::~NotificationOptionsMenuModel() {
147 }
148
IsItemForCommandIdDynamic(int command_id) const149 bool NotificationOptionsMenuModel::IsItemForCommandIdDynamic(int command_id)
150 const {
151 return command_id == kTogglePermissionCommand ||
152 command_id == kToggleExtensionCommand;
153 }
154
GetLabelForCommandId(int command_id) const155 string16 NotificationOptionsMenuModel::GetLabelForCommandId(int command_id)
156 const {
157 // TODO(tfarina,johnnyg): Remove this code if we decide to close notifications
158 // after permissions are revoked.
159 if (command_id == kTogglePermissionCommand ||
160 command_id == kToggleExtensionCommand) {
161 const Notification& notification = balloon_->notification();
162 const GURL& origin = notification.origin_url();
163
164 DesktopNotificationService* service =
165 DesktopNotificationServiceFactory::GetForProfile(balloon_->profile());
166 if (origin.SchemeIs(chrome::kExtensionScheme)) {
167 ExtensionService* ext_service =
168 balloon_->profile()->GetExtensionService();
169 const Extension* extension = ext_service->GetExtensionByURL(origin);
170 if (extension) {
171 ExtensionPrefs* extension_prefs = ext_service->extension_prefs();
172 const std::string& id = extension->id();
173 if (extension_prefs->GetExtensionState(id) == Extension::ENABLED)
174 return l10n_util::GetStringUTF16(IDS_EXTENSIONS_DISABLE);
175 else
176 return l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE);
177 }
178 } else {
179 if (service->GetContentSetting(origin) == CONTENT_SETTING_ALLOW) {
180 return l10n_util::GetStringFUTF16(
181 IDS_NOTIFICATION_BALLOON_REVOKE_MESSAGE,
182 notification.display_source());
183 } else {
184 return l10n_util::GetStringFUTF16(
185 IDS_NOTIFICATION_BALLOON_ENABLE_MESSAGE,
186 notification.display_source());
187 }
188 }
189 } else if (command_id == kOpenContentSettingsCommand) {
190 return l10n_util::GetStringUTF16(IDS_NOTIFICATIONS_SETTINGS_BUTTON);
191 }
192 return string16();
193 }
194
IsCommandIdChecked(int) const195 bool NotificationOptionsMenuModel::IsCommandIdChecked(int /* command_id */)
196 const {
197 // Nothing in the menu is checked.
198 return false;
199 }
200
IsCommandIdEnabled(int) const201 bool NotificationOptionsMenuModel::IsCommandIdEnabled(int /* command_id */)
202 const {
203 // All the menu options are always enabled.
204 return true;
205 }
206
GetAcceleratorForCommandId(int,ui::Accelerator *)207 bool NotificationOptionsMenuModel::GetAcceleratorForCommandId(
208 int /* command_id */, ui::Accelerator* /* accelerator */) {
209 // Currently no accelerators.
210 return false;
211 }
212
ExecuteCommand(int command_id)213 void NotificationOptionsMenuModel::ExecuteCommand(int command_id) {
214 DesktopNotificationService* service =
215 DesktopNotificationServiceFactory::GetForProfile(balloon_->profile());
216 ExtensionService* ext_service =
217 balloon_->profile()->GetExtensionService();
218 const GURL& origin = balloon_->notification().origin_url();
219 switch (command_id) {
220 case kTogglePermissionCommand:
221 if (service->GetContentSetting(origin) == CONTENT_SETTING_ALLOW)
222 service->DenyPermission(origin);
223 else
224 service->GrantPermission(origin);
225 break;
226 case kToggleExtensionCommand: {
227 const Extension* extension = ext_service->GetExtensionByURL(origin);
228 if (extension) {
229 ExtensionPrefs* extension_prefs = ext_service->extension_prefs();
230 const std::string& id = extension->id();
231 if (extension_prefs->GetExtensionState(id) == Extension::ENABLED)
232 ext_service->DisableExtension(id);
233 else
234 ext_service->EnableExtension(id);
235 }
236 break;
237 }
238 case kOpenContentSettingsCommand: {
239 Browser* browser =
240 BrowserList::GetLastActiveWithProfile(balloon_->profile());
241 if (!browser) {
242 // It is possible that there is no browser window (e.g. when there are
243 // background pages, or for a chrome frame process on windows).
244 browser = Browser::Create(balloon_->profile());
245 }
246 static_cast<TabContentsDelegate*>(browser)->ShowContentSettingsPage(
247 CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
248 break;
249 }
250 default:
251 NOTREACHED();
252 break;
253 }
254 }
255