notification_view.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/views/notification_view.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/utf_string_conversions.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/ui_resources.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/accessibility/accessible_view_state.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/text/text_elider.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/canvas.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/size.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/message_center_constants.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/message_center_switches.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/message_center_util.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/notification.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/notification_change_observer.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/notification_types.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/views/message_simple_view.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/button/image_button.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/image_view.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/label.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/layout/box_layout.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/layout/fill_layout.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Dimensions.
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kIconColumnWidth = message_center::kNotificationIconSize;
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kLegacyIconSize = 40;
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kIconToTextPadding = 16;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTextTopPadding = 6;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTextLeftPadding = kIconColumnWidth + kIconToTextPadding;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTextBottomPadding = 6;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kTextRightPadding = 23;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kItemTitleToMessagePadding = 3;
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonHeight = 38;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonHorizontalPadding = 16;
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonVecticalPadding = 0;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonIconTopPadding = 11;
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonIconToTitlePadding = 16;
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kButtonTitleTopPadding = 0;
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kTitleCharacterLimit = 100;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMessageCharacterLimit = 200;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Notification colors. The text background colors below are used only to keep
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// view::Label from modifying the text color and will not actually be drawn.
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// See view::Label's SetEnabledColor() and SetBackgroundColor() for details.
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kBackgroundColor = SkColorSetRGB(255, 255, 255);
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kLegacyIconBackgroundColor = SkColorSetRGB(230, 230, 230);
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kRegularTextColor = SkColorSetRGB(68, 68, 68);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kRegularTextBackgroundColor = SK_ColorWHITE;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kDimTextColor = SkColorSetRGB(136, 136, 136);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kDimTextBackgroundColor = SK_ColorBLACK;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const SkColor kButtonSeparatorColor = SkColorSetRGB(234, 234, 234);
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static.
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)views::Background* MakeBackground(SkColor color = kBackgroundColor) {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return views::Background::CreateSolidBackground(color);
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Static.
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)views::Border* MakeBorder(int top,
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          int bottom,
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          int left = kTextLeftPadding,
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          int right = kTextRightPadding,
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          SkColor color = 0x00000000) {
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (color == 0x00000000) ?
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         views::Border::CreateEmptyBorder(top, left, bottom, right) :
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         views::Border::CreateSolidSidedBorder(top, left, bottom, right, color);
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ContainerView ///////////////////////////////////////////////////////////////
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ContainerViews are vertical BoxLayout views that propagates their childrens'
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ChildPreferredSizeChanged() and ChildVisibilityChanged() calls.
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ContainerView : public views::View {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ContainerView();
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~ContainerView();
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) protected:
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void ChildVisibilityChanged(View* child) OVERRIDE;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ContainerView);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ContainerView::ContainerView() {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ContainerView::~ContainerView() {
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ContainerView::ChildPreferredSizeChanged(View* child) {
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PreferredSizeChanged();
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ContainerView::ChildVisibilityChanged(View* child) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PreferredSizeChanged();
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ItemView ////////////////////////////////////////////////////////////////////
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ItemViews are responsible for drawing each list notification item's title and
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// message next to each other within a single column.
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ItemView : public views::View {
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ItemView(const message_center::NotificationItem& item);
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~ItemView();
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void SetVisible(bool visible) OVERRIDE;
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ItemView);
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ItemView::ItemView(const message_center::NotificationItem& item) {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal,
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        0, 0, kItemTitleToMessagePadding));
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::Label* title = new views::Label(item.title);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  title->set_collapse_when_hidden(true);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  title->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  title->SetElideBehavior(views::Label::ELIDE_AT_END);
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  title->SetEnabledColor(kRegularTextColor);
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  title->SetBackgroundColor(kRegularTextBackgroundColor);
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(title);
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::Label* message = new views::Label(item.message);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message->set_collapse_when_hidden(true);
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message->SetElideBehavior(views::Label::ELIDE_AT_END);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message->SetEnabledColor(kDimTextColor);
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message->SetBackgroundColor(kDimTextBackgroundColor);
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(message);
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PreferredSizeChanged();
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SchedulePaint();
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ItemView::~ItemView() {
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ItemView::SetVisible(bool visible) {
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::View::SetVisible(visible);
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < child_count(); ++i)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    child_at(i)->SetVisible(visible);
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ProportionalImageView ///////////////////////////////////////////////////////
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ProportionalImageViews center their images to preserve their proportion.
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ProportionalImageView : public views::View {
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ProportionalImageView(const gfx::ImageSkia& image);
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~ProportionalImageView();
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Overridden from views::View:
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual gfx::Size GetPreferredSize() OVERRIDE;
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int GetHeightForWidth(int width) OVERRIDE;
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Size GetImageSizeForWidth(int width);
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::ImageSkia image_;
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ProportionalImageView);
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProportionalImageView::ProportionalImageView(const gfx::ImageSkia& image)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : image_(image) {
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProportionalImageView::~ProportionalImageView() {
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Size ProportionalImageView::GetPreferredSize() {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Size size = GetImageSizeForWidth(image_.width());
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return gfx::Size(size.width() + GetInsets().width(),
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   size.height() + GetInsets().height());
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int ProportionalImageView::GetHeightForWidth(int width) {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return GetImageSizeForWidth(width).height();
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ProportionalImageView::OnPaint(gfx::Canvas* canvas) {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::View::OnPaint(canvas);
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Size draw_size(GetImageSizeForWidth(width()));
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!draw_size.IsEmpty()) {
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::Rect draw_bounds = GetLocalBounds();
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    draw_bounds.Inset(GetInsets());
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    draw_bounds.ClampToCenteredSize(draw_size);
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::Size image_size(image_.size());
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (image_size == draw_size) {
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      canvas->DrawImageInt(image_, draw_bounds.x(), draw_bounds.y());
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Resize case
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SkPaint paint;
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      paint.setFilterBitmap(true);
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      canvas->DrawImageInt(image_, 0, 0,
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           image_size.width(), image_size.height(),
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           draw_bounds.x(), draw_bounds.y(),
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           draw_size.width(), draw_size.height(),
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           true, paint);
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Size ProportionalImageView::GetImageSizeForWidth(int width) {
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Size size = visible() ? image_.size() : gfx::Size();
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (width > 0 && !size.IsEmpty()) {
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    double proportion = size.height() / (double) size.width();
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size.SetSize(width, std::max(0.5 + width * proportion, 1.0));
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (size.height() > message_center::kNotificationMaximumImageHeight) {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int height = message_center::kNotificationMaximumImageHeight;
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      size.SetSize(std::max(0.5 + height / proportion, 1.0), height);
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return size;
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// NotificationButton //////////////////////////////////////////////////////////
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// NotificationButtons render the action buttons of notifications.
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class NotificationButton : public views::CustomButton {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NotificationButton(views::ButtonListener* listener);
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~NotificationButton();
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SetIcon(const gfx::ImageSkia& icon);
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SetTitle(const string16& title);
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Overridden from views::View:
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual gfx::Size GetPreferredSize() OVERRIDE;
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual int GetHeightForWidth(int width) OVERRIDE;
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::ImageView* icon_;
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::Label* title_;
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NotificationButton::NotificationButton(views::ButtonListener* listener)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : views::CustomButton(listener),
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      icon_(NULL),
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      title_(NULL) {
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  set_focusable(true);
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal,
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        kButtonHorizontalPadding,
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        kButtonVecticalPadding,
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        kButtonIconToTitlePadding));
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NotificationButton::~NotificationButton() {
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NotificationButton::SetIcon(const gfx::ImageSkia& image) {
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (icon_ != NULL)
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete icon_;  // This removes the icon from this view's children.
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (image.isNull()) {
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_ = NULL;
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_ = new views::ImageView();
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_->SetImageSize(gfx::Size(message_center::kNotificationButtonIconSize,
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                  message_center::kNotificationButtonIconSize));
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_->SetImage(image);
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_->SetHorizontalAlignment(views::ImageView::LEADING);
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_->SetVerticalAlignment(views::ImageView::LEADING);
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_->set_border(MakeBorder(kButtonIconTopPadding, 0, 0, 0));
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddChildViewAt(icon_, 0);
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NotificationButton::SetTitle(const string16& title) {
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (title_ != NULL)
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete title_;  // This removes the title from this view's children.
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (title.empty()) {
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_ = NULL;
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_ = new views::Label(title);
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_->SetElideBehavior(views::Label::ELIDE_AT_END);
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_->SetEnabledColor(kRegularTextColor);
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_->SetBackgroundColor(kRegularTextBackgroundColor);
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_->set_border(MakeBorder(kButtonTitleTopPadding, 0, 0, 0));
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddChildView(title_);
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Size NotificationButton::GetPreferredSize() {
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return gfx::Size(message_center::kNotificationWidth, kButtonHeight);
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int NotificationButton::GetHeightForWidth(int width) {
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return kButtonHeight;
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace message_center {
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// NotificationView ////////////////////////////////////////////////////////////
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MessageView* NotificationView::Create(const Notification& notification,
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      NotificationChangeObserver* observer,
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      bool expanded) {
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Use MessageSimpleView for simple notifications unless rich style
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // notifications are enabled. This preserves the appearance of notifications
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // created by existing code that uses webkitNotifications.
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!IsRichNotificationEnabled() &&
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      notification.type() == NOTIFICATION_TYPE_SIMPLE)
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return new MessageSimpleView(notification, observer);
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (notification.type()) {
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTIFICATION_TYPE_BASE_FORMAT:
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTIFICATION_TYPE_IMAGE:
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTIFICATION_TYPE_MULTIPLE:
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTIFICATION_TYPE_SIMPLE:
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If the caller asks for an unrecognized kind of view (entirely possible
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // if an application is running on an older version of this code that
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // doesn't have the requested kind of notification template), we'll fall
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // back to a notification instance that will provide at least basic
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // functionality.
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(WARNING) << "Unable to fulfill request for unrecognized "
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   << "notification type " << notification.type() << ". "
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   << "Falling back to simple notification type.";
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Currently all roads lead to the generic NotificationView.
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new NotificationView(notification, observer, expanded);
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NotificationView::NotificationView(const Notification& notification,
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   NotificationChangeObserver* observer,
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   bool expanded)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : MessageView(notification, observer, expanded) {
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the opaque background that's above the view's shadow.
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  background_view_ = new views::View();
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  background_view_->set_background(MakeBackground());
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the top_view_, which collects into a vertical box all content
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // at the top of the notification (to the right of the icon) except for the
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // close button.
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  top_view_ = new ContainerView();
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the title view if appropriate.
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  title_view_ = NULL;
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!notification.title().empty()) {
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_view_ = new views::Label(
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        MaybeTruncateText( notification.title(), kTitleCharacterLimit));
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (is_expanded())
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      title_view_->SetMultiLine(true);
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      title_view_->SetElideBehavior(views::Label::ELIDE_AT_END);
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_view_->SetFont(title_view_->font().DeriveFont(2));
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_view_->SetEnabledColor(kRegularTextColor);
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_view_->SetBackgroundColor(kRegularTextBackgroundColor);
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    title_view_->set_border(MakeBorder(kTextTopPadding, 3));
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    top_view_->AddChildView(title_view_);
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the message view if appropriate.
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message_view_ = NULL;
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!notification.message().empty()) {
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_view_ = new views::Label(
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        MaybeTruncateText(notification.message(), kMessageCharacterLimit));
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_view_->SetVisible(!is_expanded() || !notification.items().size());
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_view_->set_collapse_when_hidden(true);
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (is_expanded())
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      message_view_->SetMultiLine(true);
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      message_view_->SetElideBehavior(views::Label::ELIDE_AT_END);
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_view_->SetEnabledColor(kRegularTextColor);
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_view_->SetBackgroundColor(kRegularTextBackgroundColor);
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    message_view_->set_border(MakeBorder(0, 3));
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    top_view_->AddChildView(message_view_);
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the list item views (up to a maximum).
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<NotificationItem> items = notification.items();
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < items.size() && i < kNotificationMaximumItems; ++i) {
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ItemView* item_view = new ItemView(items[i]);
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    item_view->SetVisible(is_expanded());
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    item_view->set_border(MakeBorder(0, 4));
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    item_views_.push_back(item_view);
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    top_view_->AddChildView(item_view);
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the notification icon view.
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (notification.type() == NOTIFICATION_TYPE_SIMPLE) {
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    views::ImageView* icon_view = new views::ImageView();
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_view->SetImage(notification.icon().AsImageSkia());
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_view->SetImageSize(gfx::Size(kLegacyIconSize, kLegacyIconSize));
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_view->SetHorizontalAlignment(views::ImageView::CENTER);
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_view->SetVerticalAlignment(views::ImageView::CENTER);
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_view->set_background(MakeBackground(kLegacyIconBackgroundColor));
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_view_ = icon_view;
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_view_ = new ProportionalImageView(notification.icon().AsImageSkia());
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the bottom_view_, which collects into a vertical box all content
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // below the notification icon except for the expand button.
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bottom_view_ = new ContainerView();
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the image view if appropriate.
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  image_view_ = NULL;
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!notification.image().IsEmpty()) {
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    image_view_ = new ProportionalImageView(notification.image().AsImageSkia());
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    image_view_->SetVisible(is_expanded());
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bottom_view_->AddChildView(image_view_);
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create action buttons if appropriate.
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<ButtonInfo> buttons = notification.buttons();
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < buttons.size(); ++i) {
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    views::View* separator = new views::ImageView();
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    separator->set_border(MakeBorder(1, 0, 0, 0, kButtonSeparatorColor));
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bottom_view_->AddChildView(separator);
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NotificationButton* button = new NotificationButton(this);
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ButtonInfo button_info = buttons[i];
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    button->SetTitle(button_info.title);
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    button->SetIcon(button_info.icon.AsImageSkia());
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    action_buttons_.push_back(button);
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bottom_view_->AddChildView(button);
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Hide the expand button if appropriate.
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool expandable = item_views_.size() || image_view_;
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expand_button()->SetVisible(expandable && !is_expanded());
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Put together the different content and control views. Layering those allows
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // for proper layout logic and it also allows the close and expand buttons to
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // overlap the content as needed to provide large enough click and touch areas
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // (<http://crbug.com/168822> and <http://crbug.com/168856>).
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(background_view_);
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(top_view_);
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(icon_view_);
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(bottom_view_);
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(close_button());
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(expand_button());
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NotificationView::~NotificationView() {
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Size NotificationView::GetPreferredSize() {
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int top_width = top_view_->GetPreferredSize().width();
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int bottom_width = bottom_view_->GetPreferredSize().width();
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int preferred_width = std::max(top_width, bottom_width) + GetInsets().width();
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return gfx::Size(preferred_width, GetHeightForWidth(preferred_width));
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int NotificationView::GetHeightForWidth(int width) {
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Insets insets = GetInsets();
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int top_height = top_view_->GetHeightForWidth(width - insets.width());
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int bottom_height = bottom_view_->GetHeightForWidth(width - insets.width());
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int icon_size = message_center::kNotificationIconSize;
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return std::max(top_height, icon_size) + bottom_height + insets.height();
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NotificationView::Layout() {
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Insets insets = GetInsets();
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int content_width = width() - insets.width();
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int content_right = width() - insets.right();
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  background_view_->SetBounds(insets.left(), insets.top(),
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              content_width, height() - insets.height());
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int top_height = top_view_->GetHeightForWidth(content_width);
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  top_view_->SetBounds(insets.left(), insets.top(), content_width, top_height);
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int icon_size = message_center::kNotificationIconSize;
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_view_->SetBounds(insets.left(), insets.top(), icon_size, icon_size);
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int bottom_y = insets.top() + std::max(top_height, icon_size);
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int bottom_height = bottom_view_->GetHeightForWidth(content_width);
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bottom_view_->SetBounds(insets.left(), bottom_y,
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          content_width, bottom_height);
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Size close_size(close_button()->GetPreferredSize());
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  close_button()->SetBounds(content_right - close_size.width(), insets.top(),
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            close_size.width(), close_size.height());
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Size expand_size(expand_button()->GetPreferredSize());
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int expand_y = bottom_y - expand_size.height();
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expand_button()->SetBounds(content_right - expand_size.width(), expand_y,
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             expand_size.width(), expand_size.height());
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NotificationView::ButtonPressed(views::Button* sender,
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     const ui::Event& event) {
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // See if the button pressed was an action button.
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < action_buttons_.size(); ++i) {
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (sender == action_buttons_[i]) {
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      observer()->OnButtonClicked(notification_id(), i);
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Let the superclass handled anything other than action buttons.
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MessageView::ButtonPressed(sender, event);
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Show and hide subviews appropriately on expansion.
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (sender == expand_button()) {
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (message_view_ && item_views_.size())
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      message_view_->SetVisible(false);
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < item_views_.size(); ++i)
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      item_views_[i]->SetVisible(true);
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (image_view_)
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      image_view_->SetVisible(true);
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    expand_button()->SetVisible(false);
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PreferredSizeChanged();
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SchedulePaint();
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)string16 NotificationView::MaybeTruncateText(const string16& text,
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             size_t limit) {
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Currently just truncate the text by the total number of characters.
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(mukai): add better assumption like number of lines.
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!is_expanded())
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return text;
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ui::TruncateString(text, limit);
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace message_center
544