OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/message_center/views/message_view.h" | 5 #include "ui/message_center/views/message_view.h" |
6 | 6 |
7 #include "grit/ui_resources.h" | 7 #include "grit/ui_resources.h" |
8 #include "grit/ui_strings.h" | 8 #include "grit/ui_strings.h" |
9 #include "ui/base/l10n/l10n_util.h" | 9 #include "ui/base/l10n/l10n_util.h" |
10 #include "ui/base/models/simple_menu_model.h" | 10 #include "ui/base/models/simple_menu_model.h" |
11 #include "ui/base/resource/resource_bundle.h" | 11 #include "ui/base/resource/resource_bundle.h" |
12 #include "ui/compositor/scoped_layer_animation_settings.h" | 12 #include "ui/compositor/scoped_layer_animation_settings.h" |
13 #include "ui/gfx/canvas.h" | 13 #include "ui/gfx/canvas.h" |
14 #include "ui/gfx/shadow_value.h" | 14 #include "ui/gfx/shadow_value.h" |
15 #include "ui/gfx/skia_util.h" | 15 #include "ui/gfx/skia_util.h" |
16 #include "ui/message_center/message_center_util.h" | 16 #include "ui/message_center/message_center_util.h" |
| 17 #include "ui/message_center/notification_change_observer.h" |
17 #include "ui/views/controls/button/image_button.h" | 18 #include "ui/views/controls/button/image_button.h" |
18 #include "ui/views/controls/menu/menu_model_adapter.h" | 19 #include "ui/views/controls/menu/menu_model_adapter.h" |
19 #include "ui/views/controls/menu/menu_runner.h" | 20 #include "ui/views/controls/menu/menu_runner.h" |
20 #include "ui/views/controls/scroll_view.h" | 21 #include "ui/views/controls/scroll_view.h" |
21 #include "ui/views/widget/widget.h" | 22 #include "ui/views/widget/widget.h" |
22 | 23 |
23 namespace { | 24 namespace { |
24 | 25 |
25 const int kCloseButtonSize = 29; | 26 const int kControlButtonSize = 29; |
26 const int kCloseIconTopPadding = 5; | 27 const int kCloseIconTopPadding = 5; |
27 const int kCloseIconRightPadding = 5; | 28 const int kCloseIconRightPadding = 5; |
| 29 const int kExpandIconBottomPadding = 8; |
| 30 const int kExpandIconRightPadding = 11; |
| 31 |
28 const int kShadowOffset = 1; | 32 const int kShadowOffset = 1; |
29 const int kShadowBlur = 4; | 33 const int kShadowBlur = 4; |
30 | 34 |
31 const SkColor kShadowColor = SkColorSetARGB(0.3 * 255, 0, 0, 0); | 35 const SkColor kShadowColor = SkColorSetARGB(0.3 * 255, 0, 0, 0); |
32 const SkColor kTransparentColor = SkColorSetARGB(0, 0, 0, 0); | 36 const SkColor kTransparentColor = SkColorSetARGB(0, 0, 0, 0); |
33 | 37 |
34 // Menu constants | 38 // Menu constants |
35 const int kTogglePermissionCommand = 0; | 39 const int kTogglePermissionCommand = 0; |
36 const int kToggleExtensionCommand = 1; | 40 const int kToggleExtensionCommand = 1; |
37 const int kShowSettingsCommand = 2; | 41 const int kShowSettingsCommand = 2; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 resource_id)); | 101 resource_id)); |
98 } | 102 } |
99 | 103 |
100 void ControlButton::SetPressedImage(int resource_id) { | 104 void ControlButton::SetPressedImage(int resource_id) { |
101 SetImage(views::CustomButton::STATE_PRESSED, | 105 SetImage(views::CustomButton::STATE_PRESSED, |
102 ResourceBundle::GetSharedInstance().GetImageSkiaNamed( | 106 ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
103 resource_id)); | 107 resource_id)); |
104 } | 108 } |
105 | 109 |
106 gfx::Size ControlButton::GetPreferredSize() { | 110 gfx::Size ControlButton::GetPreferredSize() { |
107 return gfx::Size(kCloseButtonSize, kCloseButtonSize); | 111 return gfx::Size(kControlButtonSize, kControlButtonSize); |
108 } | 112 } |
109 | 113 |
110 void ControlButton::OnPaint(gfx::Canvas* canvas) { | 114 void ControlButton::OnPaint(gfx::Canvas* canvas) { |
111 // This is the same implementation as ImageButton::OnPaint except | 115 // This is the same implementation as ImageButton::OnPaint except |
112 // that it calls ComputePaddedImagePaintPosition() instead of | 116 // that it calls ComputePaddedImagePaintPosition() instead of |
113 // ComputeImagePaintPosition(), in effect overriding that private method. | 117 // ComputeImagePaintPosition(), in effect overriding that private method. |
114 View::OnPaint(canvas); | 118 View::OnPaint(canvas); |
115 gfx::ImageSkia image = GetImageToPaint(); | 119 gfx::ImageSkia image = GetImageToPaint(); |
116 if (!image.isNull()) { | 120 if (!image.isNull()) { |
117 gfx::Point position = ComputePaddedImagePaintPosition(image); | 121 gfx::Point position = ComputePaddedImagePaintPosition(image); |
(...skipping 26 matching lines...) Expand all Loading... |
144 } | 148 } |
145 | 149 |
146 // A border to provide the shadow for each card. | 150 // A border to provide the shadow for each card. |
147 // Current shadow should look like css box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) | 151 // Current shadow should look like css box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) |
148 class ShadowBorder : public views::Border { | 152 class ShadowBorder : public views::Border { |
149 public: | 153 public: |
150 ShadowBorder() : views::Border() {} | 154 ShadowBorder() : views::Border() {} |
151 virtual ~ShadowBorder() {} | 155 virtual ~ShadowBorder() {} |
152 | 156 |
153 protected: | 157 protected: |
154 // views::Border overrides: | 158 // Overridden from views::Border: |
155 virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE; | 159 virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE; |
156 virtual gfx::Insets GetInsets() const OVERRIDE; | 160 virtual gfx::Insets GetInsets() const OVERRIDE; |
157 | 161 |
158 DISALLOW_COPY_AND_ASSIGN(ShadowBorder); | 162 DISALLOW_COPY_AND_ASSIGN(ShadowBorder); |
159 }; | 163 }; |
160 | 164 |
161 void ShadowBorder::Paint(const views::View& view, gfx::Canvas* canvas) { | 165 void ShadowBorder::Paint(const views::View& view, gfx::Canvas* canvas) { |
162 SkPaint paint; | 166 SkPaint paint; |
163 std::vector<gfx::ShadowValue> shadows; | 167 std::vector<gfx::ShadowValue> shadows; |
164 shadows.push_back(gfx::ShadowValue(gfx::Point(), kShadowBlur, kShadowColor)); | 168 shadows.push_back(gfx::ShadowValue(gfx::Point(), kShadowBlur, kShadowColor)); |
165 skia::RefPtr<SkDrawLooper> looper = gfx::CreateShadowDrawLooper(shadows); | 169 skia::RefPtr<SkDrawLooper> looper = gfx::CreateShadowDrawLooper(shadows); |
166 paint.setLooper(looper.get()); | 170 paint.setLooper(looper.get()); |
167 paint.setColor(kTransparentColor); | 171 paint.setColor(kTransparentColor); |
168 paint.setStrokeJoin(SkPaint::kRound_Join); | 172 paint.setStrokeJoin(SkPaint::kRound_Join); |
169 gfx::Rect bounds(view.size()); | 173 gfx::Rect bounds(view.size()); |
170 bounds.Inset(gfx::Insets(kShadowBlur / 2, kShadowBlur / 2, | 174 bounds.Inset(gfx::Insets(kShadowBlur / 2, kShadowBlur / 2, |
171 kShadowBlur / 2, kShadowBlur / 2)); | 175 kShadowBlur / 2, kShadowBlur / 2)); |
172 canvas->DrawRect(bounds, paint); | 176 canvas->DrawRect(bounds, paint); |
173 } | 177 } |
174 | 178 |
175 gfx::Insets ShadowBorder::GetInsets() const { | 179 gfx::Insets ShadowBorder::GetInsets() const { |
176 return message_center::MessageView::GetShadowInsets(); | 180 return message_center::MessageView::GetShadowInsets(); |
177 } | 181 } |
178 | 182 |
179 // A dropdown menu for notifications. | 183 // A dropdown menu for notifications. |
180 class MenuModel : public ui::SimpleMenuModel, | 184 class MenuModel : public ui::SimpleMenuModel, |
181 public ui::SimpleMenuModel::Delegate { | 185 public ui::SimpleMenuModel::Delegate { |
182 public: | 186 public: |
183 MenuModel(message_center::NotificationList::Delegate* list_delegate, | 187 MenuModel(message_center::NotificationChangeObserver* observer, |
184 const std::string& notification_id, | 188 const std::string& notification_id, |
185 const string16& display_source, | 189 const string16& display_source, |
186 const std::string& extension_id); | 190 const std::string& extension_id); |
187 virtual ~MenuModel(); | 191 virtual ~MenuModel(); |
188 | 192 |
189 // Overridden from ui::SimpleMenuModel::Delegate: | 193 // Overridden from ui::SimpleMenuModel::Delegate: |
190 virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE; | 194 virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE; |
191 virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; | 195 virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; |
192 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; | 196 virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; |
193 virtual bool GetAcceleratorForCommandId( | 197 virtual bool GetAcceleratorForCommandId( |
194 int command_id, | 198 int command_id, |
195 ui::Accelerator* accelerator) OVERRIDE; | 199 ui::Accelerator* accelerator) OVERRIDE; |
196 virtual void ExecuteCommand(int command_id) OVERRIDE; | 200 virtual void ExecuteCommand(int command_id) OVERRIDE; |
197 | 201 |
198 private: | 202 private: |
199 message_center::NotificationList::Delegate* list_delegate_; | 203 message_center::NotificationChangeObserver* observer_; // Weak reference. |
200 // Weak, global MessageCenter | |
201 std::string notification_id_; | 204 std::string notification_id_; |
202 | 205 |
203 DISALLOW_COPY_AND_ASSIGN(MenuModel); | 206 DISALLOW_COPY_AND_ASSIGN(MenuModel); |
204 }; | 207 }; |
205 | 208 |
206 MenuModel::MenuModel(message_center::NotificationList::Delegate* list_delegate, | 209 MenuModel::MenuModel(message_center::NotificationChangeObserver* observer, |
207 const std::string& notification_id, | 210 const std::string& notification_id, |
208 const string16& display_source, | 211 const string16& display_source, |
209 const std::string& extension_id) | 212 const std::string& extension_id) |
210 : ALLOW_THIS_IN_INITIALIZER_LIST(ui::SimpleMenuModel(this)), | 213 : ALLOW_THIS_IN_INITIALIZER_LIST(ui::SimpleMenuModel(this)), |
211 list_delegate_(list_delegate), | 214 observer_(observer), |
212 notification_id_(notification_id) { | 215 notification_id_(notification_id) { |
213 // Add 'disable notifications' menu item. | 216 // Add 'disable notifications' menu item. |
214 if (!extension_id.empty()) { | 217 if (!extension_id.empty()) { |
215 AddItem(kToggleExtensionCommand, | 218 AddItem(kToggleExtensionCommand, |
216 l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_EXTENSIONS_DISABLE)); | 219 l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_EXTENSIONS_DISABLE)); |
217 } else if (!display_source.empty()) { | 220 } else if (!display_source.empty()) { |
218 AddItem(kTogglePermissionCommand, | 221 AddItem(kTogglePermissionCommand, |
219 l10n_util::GetStringFUTF16(IDS_MESSAGE_CENTER_SITE_DISABLE, | 222 l10n_util::GetStringFUTF16(IDS_MESSAGE_CENTER_SITE_DISABLE, |
220 display_source)); | 223 display_source)); |
221 } | 224 } |
(...skipping 20 matching lines...) Expand all Loading... |
242 } | 245 } |
243 | 246 |
244 bool MenuModel::GetAcceleratorForCommandId(int command_id, | 247 bool MenuModel::GetAcceleratorForCommandId(int command_id, |
245 ui::Accelerator* accelerator) { | 248 ui::Accelerator* accelerator) { |
246 return false; | 249 return false; |
247 } | 250 } |
248 | 251 |
249 void MenuModel::ExecuteCommand(int command_id) { | 252 void MenuModel::ExecuteCommand(int command_id) { |
250 switch (command_id) { | 253 switch (command_id) { |
251 case kToggleExtensionCommand: | 254 case kToggleExtensionCommand: |
252 list_delegate_->DisableNotificationByExtension(notification_id_); | 255 observer_->OnDisableNotificationsByExtension(notification_id_); |
253 break; | 256 break; |
254 case kTogglePermissionCommand: | 257 case kTogglePermissionCommand: |
255 list_delegate_->DisableNotificationByUrl(notification_id_); | 258 observer_->OnDisableNotificationsByUrl(notification_id_); |
256 break; | 259 break; |
257 case kShowSettingsCommand: | 260 case kShowSettingsCommand: |
258 list_delegate_->ShowNotificationSettings(notification_id_); | 261 observer_->OnShowNotificationSettings(notification_id_); |
259 break; | 262 break; |
260 default: | 263 default: |
261 NOTREACHED(); | 264 NOTREACHED(); |
262 } | 265 } |
263 } | 266 } |
264 | 267 |
265 } // namespace | 268 } // namespace |
266 | 269 |
267 namespace message_center { | 270 namespace message_center { |
268 | 271 |
269 MessageView::MessageView(NotificationList::Delegate* list_delegate, | 272 MessageView::MessageView(const Notification& notification, |
270 const Notification& notification) | 273 NotificationChangeObserver* observer, |
271 : list_delegate_(list_delegate), | 274 bool expanded) |
| 275 : observer_(observer), |
272 notification_id_(notification.id()), | 276 notification_id_(notification.id()), |
273 display_source_(notification.display_source()), | 277 display_source_(notification.display_source()), |
274 extension_id_(notification.extension_id()), | 278 extension_id_(notification.extension_id()), |
275 scroller_(NULL) { | 279 scroller_(NULL), |
| 280 is_expanded_(expanded) { |
276 ControlButton *close = new ControlButton(this); | 281 ControlButton *close = new ControlButton(this); |
277 close->SetPadding(-kCloseIconRightPadding, kCloseIconTopPadding); | 282 close->SetPadding(-kCloseIconRightPadding, kCloseIconTopPadding); |
278 close->SetNormalImage(IDR_NOTIFICATION_CLOSE); | 283 close->SetNormalImage(IDR_NOTIFICATION_CLOSE); |
279 close->SetHoveredImage(IDR_NOTIFICATION_CLOSE_HOVER); | 284 close->SetHoveredImage(IDR_NOTIFICATION_CLOSE_HOVER); |
280 close->SetPressedImage(IDR_NOTIFICATION_CLOSE_PRESSED); | 285 close->SetPressedImage(IDR_NOTIFICATION_CLOSE_PRESSED); |
| 286 close->set_owned_by_client(); |
281 close_button_.reset(close); | 287 close_button_.reset(close); |
| 288 |
| 289 ControlButton *expand = new ControlButton(this); |
| 290 expand->SetPadding(-kExpandIconRightPadding, -kExpandIconBottomPadding); |
| 291 expand->SetNormalImage(IDR_NOTIFICATIONS_EXPAND); |
| 292 expand->SetHoveredImage(IDR_NOTIFICATIONS_EXPAND_HOVER); |
| 293 expand->SetPressedImage(IDR_NOTIFICATIONS_EXPAND_PRESSED); |
| 294 expand->set_owned_by_client(); |
| 295 expand_button_.reset(expand); |
| 296 |
282 if (IsRichNotificationEnabled()) | 297 if (IsRichNotificationEnabled()) |
283 set_border(new ShadowBorder()); | 298 set_border(new ShadowBorder()); |
284 } | 299 } |
285 | 300 |
286 MessageView::MessageView() { | 301 MessageView::MessageView() { |
287 } | 302 } |
288 | 303 |
289 MessageView::~MessageView() { | 304 MessageView::~MessageView() { |
290 } | 305 } |
291 | 306 |
292 // static | 307 // static |
293 gfx::Insets MessageView::GetShadowInsets() { | 308 gfx::Insets MessageView::GetShadowInsets() { |
294 return gfx::Insets(kShadowBlur / 2 - kShadowOffset, | 309 return gfx::Insets(kShadowBlur / 2 - kShadowOffset, |
295 kShadowBlur / 2, | 310 kShadowBlur / 2, |
296 kShadowBlur / 2 + kShadowOffset, | 311 kShadowBlur / 2 + kShadowOffset, |
297 kShadowBlur / 2); | 312 kShadowBlur / 2); |
298 } | 313 } |
299 | 314 |
| 315 void MessageView::Update(const Notification& notification) { |
| 316 notification_id_ = notification.id(); |
| 317 display_source_ = notification.display_source(); |
| 318 extension_id_ = notification.extension_id(); |
| 319 } |
| 320 |
300 bool MessageView::OnMousePressed(const ui::MouseEvent& event) { | 321 bool MessageView::OnMousePressed(const ui::MouseEvent& event) { |
301 if (event.flags() & ui::EF_RIGHT_MOUSE_BUTTON) { | 322 if (event.flags() & ui::EF_RIGHT_MOUSE_BUTTON) { |
302 ShowMenu(event.location()); | 323 ShowMenu(event.location()); |
303 return true; | 324 return true; |
304 } | 325 } |
305 list_delegate_->OnNotificationClicked(notification_id_); | 326 observer_->OnClicked(notification_id_); |
306 return true; | 327 return true; |
307 } | 328 } |
308 | 329 |
309 void MessageView::OnGestureEvent(ui::GestureEvent* event) { | 330 void MessageView::OnGestureEvent(ui::GestureEvent* event) { |
310 if (event->type() == ui::ET_GESTURE_TAP) { | 331 if (event->type() == ui::ET_GESTURE_TAP) { |
311 list_delegate_->OnNotificationClicked(notification_id_); | 332 observer_->OnClicked(notification_id_); |
312 event->SetHandled(); | 333 event->SetHandled(); |
313 return; | 334 return; |
314 } | 335 } |
315 | 336 |
316 if (event->type() == ui::ET_GESTURE_LONG_PRESS) { | 337 if (event->type() == ui::ET_GESTURE_LONG_PRESS) { |
317 ShowMenu(event->location()); | 338 ShowMenu(event->location()); |
318 event->SetHandled(); | 339 event->SetHandled(); |
319 return; | 340 return; |
320 } | 341 } |
321 | 342 |
322 SlideOutView::OnGestureEvent(event); | 343 SlideOutView::OnGestureEvent(event); |
323 // Do not return here by checking handled(). SlideOutView calls SetHandled() | 344 // Do not return here by checking handled(). SlideOutView calls SetHandled() |
324 // even though the scroll gesture doesn't make no (or little) effects on the | 345 // even though the scroll gesture doesn't make no (or little) effects on the |
325 // slide-out behavior. See http://crbug.com/172991 | 346 // slide-out behavior. See http://crbug.com/172991 |
326 | 347 |
327 if (!event->IsScrollGestureEvent()) | 348 if (!event->IsScrollGestureEvent()) |
328 return; | 349 return; |
329 | 350 |
330 if (scroller_) | 351 if (scroller_) |
331 scroller_->OnGestureEvent(event); | 352 scroller_->OnGestureEvent(event); |
332 event->SetHandled(); | 353 event->SetHandled(); |
333 } | 354 } |
334 | 355 |
335 void MessageView::ButtonPressed(views::Button* sender, | 356 void MessageView::ButtonPressed(views::Button* sender, |
336 const ui::Event& event) { | 357 const ui::Event& event) { |
337 if (sender == close_button()) | 358 if (sender == close_button()) { |
338 list_delegate_->SendRemoveNotification(notification_id_, true); // By user. | 359 observer_->OnRemoveNotification(notification_id_, true); // By user. |
| 360 } else if (sender == expand_button()) { |
| 361 is_expanded_ = true; |
| 362 observer_->OnExpanded(notification_id_); |
| 363 } |
339 } | 364 } |
340 | 365 |
341 void MessageView::ShowMenu(gfx::Point screen_location) { | 366 void MessageView::ShowMenu(gfx::Point screen_location) { |
342 MenuModel menu_model(list_delegate_, notification_id_, | 367 MenuModel menu_model(observer_, notification_id_, |
343 display_source_, extension_id_); | 368 display_source_, extension_id_); |
344 if (menu_model.GetItemCount() == 0) | 369 if (menu_model.GetItemCount() == 0) |
345 return; | 370 return; |
346 | 371 |
347 views::MenuModelAdapter menu_model_adapter(&menu_model); | 372 views::MenuModelAdapter menu_model_adapter(&menu_model); |
348 views::MenuRunner menu_runner(menu_model_adapter.CreateMenu()); | 373 views::MenuRunner menu_runner(menu_model_adapter.CreateMenu()); |
349 | 374 |
350 views::View::ConvertPointToScreen(this, &screen_location); | 375 views::View::ConvertPointToScreen(this, &screen_location); |
351 ignore_result(menu_runner.RunMenuAt( | 376 ignore_result(menu_runner.RunMenuAt( |
352 GetWidget()->GetTopLevelWidget(), | 377 GetWidget()->GetTopLevelWidget(), |
353 NULL, | 378 NULL, |
354 gfx::Rect(screen_location, gfx::Size()), | 379 gfx::Rect(screen_location, gfx::Size()), |
355 views::MenuItemView::TOPRIGHT, | 380 views::MenuItemView::TOPRIGHT, |
356 views::MenuRunner::HAS_MNEMONICS)); | 381 views::MenuRunner::HAS_MNEMONICS)); |
357 } | 382 } |
358 | 383 |
359 void MessageView::OnSlideOut() { | 384 void MessageView::OnSlideOut() { |
360 list_delegate_->SendRemoveNotification(notification_id_, true); // By user. | 385 observer_->OnRemoveNotification(notification_id_, true); // By user. |
361 } | 386 } |
362 | 387 |
363 } // namespace message_center | 388 } // namespace message_center |
OLD | NEW |