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"
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/stl_util.h"
97d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h"
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/base/cursor/cursor.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/layout.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/canvas.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/size.h"
152385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "ui/gfx/skia_util.h"
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/gfx/text_elider.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/message_center/message_center.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/message_center/message_center_style.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/notification.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/message_center/notification_types.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/message_center/views/bounded_label.h"
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/message_center/views/constants.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/message_center/views/message_center_controller.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/message_center/views/notification_button.h"
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/message_center/views/padded_button.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/message_center/views/proportional_image_view.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme.h"
2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/resources/grit/ui_resources.h"
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/strings/grit/ui_strings.h"
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/background.h"
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/border.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/button/image_button.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/image_view.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/controls/label.h"
35a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "ui/views/controls/progress_bar.h"
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/layout/box_layout.h"
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/layout/fill_layout.h"
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/views/native_cursor.h"
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/views/painter.h"
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/views/view_targeter.h"
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/widget/widget.h"
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Dimensions.
46a3f7b4e666c476898878fa745f637129375cd889Ben Murdochconst int kProgressBarWidth = message_center::kNotificationWidth -
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    message_center::kTextLeftPadding - message_center::kTextRightPadding;
482385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdochconst int kProgressBarBottomPadding = 0;
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<views::Border> MakeEmptyBorder(int top,
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          int left,
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          int bottom,
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          int right) {
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return views::Border::CreateEmptyBorder(top, left, bottom, right);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<views::Border> MakeTextBorder(int padding, int top, int bottom) {
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Split the padding between the top and the bottom, then add the extra space.
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return MakeEmptyBorder(padding / 2 + top,
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         message_center::kTextLeftPadding,
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         (padding + 1) / 2 + bottom,
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         message_center::kTextRightPadding);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<views::Border> MakeProgressBarBorder(int top, int bottom) {
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return MakeEmptyBorder(top,
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         message_center::kTextLeftPadding,
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         bottom,
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         message_center::kTextRightPadding);
73a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
74a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
75a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// static
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<views::Border> MakeSeparatorBorder(int top,
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              int left,
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              SkColor color) {
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return views::Border::CreateSolidSidedBorder(top, left, 0, 0, color);
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Return true if and only if the image is null or has alpha.
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool HasAlpha(gfx::ImageSkia& image, views::Widget* widget) {
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Determine which bitmap to use.
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float factor = 1.0f;
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (widget)
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    factor = ui::GetScaleFactorForNativeView(widget->GetNativeView());
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Extract that bitmap's alpha and look for a non-opaque pixel there.
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SkBitmap bitmap = image.GetRepresentation(factor).sk_bitmap();
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!bitmap.isNull()) {
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SkBitmap alpha;
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bitmap.extractAlpha(&alpha);
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (int y = 0; y < bitmap.height(); ++y) {
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      for (int x = 0; x < bitmap.width(); ++x) {
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (alpha.getColor(x, y) != SK_ColorBLACK) {
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          return true;
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If no opaque pixel was found, return false unless the bitmap is empty.
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return bitmap.isNull();
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ItemView ////////////////////////////////////////////////////////////////////
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ItemViews are responsible for drawing each list notification item's title and
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// message next to each other within a single column.
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ItemView : public views::View {
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ItemView(const message_center::NotificationItem& item);
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~ItemView();
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Overridden from views::View:
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,
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      0, 0, message_center::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);
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  title->SetEnabledColor(message_center::kRegularTextColor);
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  title->SetBackgroundColor(message_center::kRegularTextBackgroundColor);
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(title);
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::Label* message = new views::Label(item.message);
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message->set_collapse_when_hidden(true);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  message->SetHorizontalAlignment(gfx::ALIGN_LEFT);
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  message->SetEnabledColor(message_center::kDimTextColor);
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  message->SetBackgroundColor(message_center::kDimTextBackgroundColor);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(message);
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PreferredSizeChanged();
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SchedulePaint();
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ItemView::~ItemView() {
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ItemView::SetVisible(bool visible) {
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::View::SetVisible(visible);
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < child_count(); ++i)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    child_at(i)->SetVisible(visible);
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The NotificationImage is the view representing the area covered by the
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// notification's image, including background and border.  Its size can be
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// specified in advance and images will be scaled to fit including a border if
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// necessary.
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)views::View* MakeNotificationImage(const gfx::Image& image, gfx::Size size) {
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  views::View* container = new views::View();
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  container->SetLayoutManager(new views::FillLayout());
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  container->set_background(views::Background::CreateSolidBackground(
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      message_center::kImageBackgroundColor));
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::Size ideal_size(
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      message_center::kNotificationPreferredImageWidth,
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      message_center::kNotificationPreferredImageHeight);
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  gfx::Size scaled_size =
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      message_center::GetImageSizeForContainerSize(ideal_size, image.Size());
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  views::View* proportional_image_view =
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new message_center::ProportionalImageView(image.AsImageSkia(),
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                ideal_size);
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This calculation determines that the new image would have the correct
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // height for width.
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ideal_size != scaled_size) {
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    proportional_image_view->SetBorder(views::Border::CreateSolidBorder(
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        message_center::kNotificationImageBorderSize, SK_ColorTRANSPARENT));
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  container->AddChildView(proportional_image_view);
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return container;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
188a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch// NotificationProgressBar /////////////////////////////////////////////////////
189a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
190a3f7b4e666c476898878fa745f637129375cd889Ben Murdochclass NotificationProgressBar : public views::ProgressBar {
191a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch public:
192a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  NotificationProgressBar();
193a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  virtual ~NotificationProgressBar();
194a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
195a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch private:
196a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  // Overriden from View
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual gfx::Size GetPreferredSize() const OVERRIDE;
1982385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
199a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
200a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(NotificationProgressBar);
201a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch};
202a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
203a3f7b4e666c476898878fa745f637129375cd889Ben MurdochNotificationProgressBar::NotificationProgressBar() {
204a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
205a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
206a3f7b4e666c476898878fa745f637129375cd889Ben MurdochNotificationProgressBar::~NotificationProgressBar() {
207a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
208a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size NotificationProgressBar::GetPreferredSize() const {
2102385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  gfx::Size pref_size(kProgressBarWidth, message_center::kProgressBarThickness);
211a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  gfx::Insets insets = GetInsets();
212a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  pref_size.Enlarge(insets.width(), insets.height());
213a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  return pref_size;
214a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch}
215a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
2162385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdochvoid NotificationProgressBar::OnPaint(gfx::Canvas* canvas) {
2172385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  gfx::Rect content_bounds = GetContentsBounds();
2182385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
2192385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  // Draw background.
2202385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  SkPath background_path;
2212385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  background_path.addRoundRect(gfx::RectToSkRect(content_bounds),
2222385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch                               message_center::kProgressBarCornerRadius,
2232385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch                               message_center::kProgressBarCornerRadius);
2242385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  SkPaint background_paint;
2252385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  background_paint.setStyle(SkPaint::kFill_Style);
2262385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  background_paint.setFlags(SkPaint::kAntiAlias_Flag);
2272385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  background_paint.setColor(message_center::kProgressBarBackgroundColor);
2282385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  canvas->DrawPath(background_path, background_paint);
2292385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
2302385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  // Draw slice.
2312385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  const int slice_width =
2322385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      static_cast<int>(content_bounds.width() * GetNormalizedValue() + 0.5);
2332385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  if (slice_width < 1)
2342385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    return;
2352385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
2362385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  gfx::Rect slice_bounds = content_bounds;
2372385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  slice_bounds.set_width(slice_width);
2382385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  SkPath slice_path;
2392385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  slice_path.addRoundRect(gfx::RectToSkRect(slice_bounds),
2402385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch                          message_center::kProgressBarCornerRadius,
2412385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch                          message_center::kProgressBarCornerRadius);
2422385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  SkPaint slice_paint;
2432385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  slice_paint.setStyle(SkPaint::kFill_Style);
2442385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  slice_paint.setFlags(SkPaint::kAntiAlias_Flag);
2452385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  slice_paint.setColor(message_center::kProgressBarSliceColor);
2462385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  canvas->DrawPath(slice_path, slice_paint);
2472385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch}
2482385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace message_center {
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// NotificationView ////////////////////////////////////////////////////////////
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NotificationView* NotificationView::Create(MessageCenterController* controller,
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           const Notification& notification,
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                           bool top_level) {
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (notification.type()) {
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTIFICATION_TYPE_BASE_FORMAT:
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTIFICATION_TYPE_IMAGE:
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTIFICATION_TYPE_MULTIPLE:
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case NOTIFICATION_TYPE_SIMPLE:
264a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    case NOTIFICATION_TYPE_PROGRESS:
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If the caller asks for an unrecognized kind of view (entirely possible
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // if an application is running on an older version of this code that
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // doesn't have the requested kind of notification template), we'll fall
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // back to a notification instance that will provide at least basic
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // functionality.
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(WARNING) << "Unable to fulfill request for unrecognized "
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   << "notification type " << notification.type() << ". "
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   << "Falling back to simple notification type.";
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Currently all roads lead to the generic NotificationView.
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  NotificationView* notification_view =
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new NotificationView(controller, notification);
2807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
2827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Don't create shadows for notification toasts on linux wih aura.
2837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (top_level)
2847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return notification_view;
2857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#endif
2867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  notification_view->CreateShadowBorder();
2887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return notification_view;
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)views::View* NotificationView::TargetForRect(views::View* root,
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                             const gfx::Rect& rect) {
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK_EQ(root, this);
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(tdanderson): Modify this function to support rect-based event
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // targeting. Using the center point of |rect| preserves this function's
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // expected behavior for the time being.
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  gfx::Point point = rect.CenterPoint();
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Want to return this for underlying views, otherwise GetCursor is not
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // called. But buttons are exceptions, they'll have their own event handlings.
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<views::View*> buttons(action_buttons_.begin(),
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                    action_buttons_.end());
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  buttons.push_back(close_button());
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (size_t i = 0; i < buttons.size(); ++i) {
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    gfx::Point point_in_child = point;
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ConvertPointToTarget(this, buttons[i], &point_in_child);
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (buttons[i]->HitTestPoint(point_in_child))
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return buttons[i]->GetEventHandlerForPoint(point_in_child);
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return root;
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3160de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void NotificationView::CreateOrUpdateViews(const Notification& notification) {
3170de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  CreateOrUpdateTitleView(notification);
3180de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  CreateOrUpdateMessageView(notification);
3190de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  CreateOrUpdateContextMessageView(notification);
3200de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  CreateOrUpdateProgressBarView(notification);
3210de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  CreateOrUpdateListItemViews(notification);
3220de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  CreateOrUpdateIconView(notification);
3230de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  CreateOrUpdateImageView(notification);
3240de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  CreateOrUpdateActionButtonViews(notification);
3250de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
3260de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
3270de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void NotificationView::SetAccessibleName(const Notification& notification) {
3280de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  std::vector<base::string16> accessible_lines;
3290de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  accessible_lines.push_back(notification.title());
3300de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  accessible_lines.push_back(notification.message());
3310de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  accessible_lines.push_back(notification.context_message());
3320de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  std::vector<NotificationItem> items = notification.items();
3330de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  for (size_t i = 0; i < items.size() && i < kNotificationMaximumItems; ++i) {
3340de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    accessible_lines.push_back(items[i].title + base::ASCIIToUTF16(" ") +
3350de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                               items[i].message);
3360de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
3370de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  set_accessible_name(JoinString(accessible_lines, '\n'));
3380de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
3390de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NotificationView::NotificationView(MessageCenterController* controller,
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   const Notification& notification)
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : MessageView(this,
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  notification.id(),
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  notification.notifier_id(),
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  notification.small_image().AsImageSkia(),
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  notification.display_source()),
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      controller_(controller),
3480de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      clickable_(notification.clickable()),
3490de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      top_view_(NULL),
3500de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      title_view_(NULL),
3510de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      message_view_(NULL),
3520de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      context_message_view_(NULL),
3530de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      icon_view_(NULL),
3540de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      bottom_view_(NULL),
3550de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      image_view_(NULL),
3560de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      progress_bar_view_(NULL) {
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the top_view_, which collects into a vertical box all content
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // at the top of the notification (to the right of the icon) except for the
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // close button.
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  top_view_ = new views::View();
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  top_view_->SetLayoutManager(
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  top_view_->SetBorder(
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      MakeEmptyBorder(kTextTopPadding - 8, 0, kTextBottomPadding - 5, 0));
3650de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  AddChildView(top_view_);
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the bottom_view_, which collects into a vertical box all content
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // below the notification icon.
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bottom_view_ = new views::View();
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bottom_view_->SetLayoutManager(
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
3710de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  AddChildView(bottom_view_);
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3730de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  CreateOrUpdateViews(notification);
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Put together the different content and control views. Layering those allows
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // for proper layout logic and it also allows the close button and small
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // image to overlap the content as needed to provide large enough click and
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // touch areas (<http://crbug.com/168822> and <http://crbug.com/168856>).
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AddChildView(small_image());
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AddChildView(close_button());
3810de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  SetAccessibleName(notification);
3825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  SetEventTargeter(
3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)NotificationView::~NotificationView() {
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)gfx::Size NotificationView::GetPreferredSize() const {
3910de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  int top_width = top_view_->GetPreferredSize().width() +
3920de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                  icon_view_->GetPreferredSize().width();
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int bottom_width = bottom_view_->GetPreferredSize().width();
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int preferred_width = std::max(top_width, bottom_width) + GetInsets().width();
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return gfx::Size(preferred_width, GetHeightForWidth(preferred_width));
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int NotificationView::GetHeightForWidth(int width) const {
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Get the height assuming no line limit changes.
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int content_width = width - GetInsets().width();
401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int top_height = top_view_->GetHeightForWidth(content_width);
402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int bottom_height = bottom_view_->GetHeightForWidth(content_width);
403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // <http://crbug.com/230448> Fix: Adjust the height when the message_view's
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // line limit would be different for the specified width than it currently is.
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TODO(dharcourt): Avoid BoxLayout and directly compute the correct height.
407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (message_view_) {
408010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    int title_lines = 0;
409010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (title_view_) {
410010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      title_lines = title_view_->GetLinesForWidthAndLimit(width,
411010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                                          kMaxTitleLines);
412010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int used_limit = message_view_->GetLineLimit();
414010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    int correct_limit = GetMessageLineLimit(title_lines, width);
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (used_limit != correct_limit) {
416f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      top_height -= GetMessageHeight(content_width, used_limit);
417f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      top_height += GetMessageHeight(content_width, correct_limit);
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
421f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int content_height = std::max(top_height, kIconSize) + bottom_height;
422f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Adjust the height to make sure there is at least 16px of space below the
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // icon if there is any space there (<http://crbug.com/232966>).
425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (content_height > kIconSize)
426ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    content_height = std::max(content_height,
427ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                              kIconSize + message_center::kIconBottomPadding);
428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return content_height + GetInsets().height();
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NotificationView::Layout() {
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MessageView::Layout();
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Insets insets = GetInsets();
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int content_width = width() - insets.width();
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Before any resizing, set or adjust the number of message lines.
438010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  int title_lines = 0;
439010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (title_view_) {
440010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    title_lines =
441010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        title_view_->GetLinesForWidthAndLimit(width(), kMaxTitleLines);
442010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (message_view_)
444010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    message_view_->SetLineLimit(GetMessageLineLimit(title_lines, width()));
445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Top views.
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int top_height = top_view_->GetHeightForWidth(content_width);
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  top_view_->SetBounds(insets.left(), insets.top(), content_width, top_height);
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Icon.
451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  icon_view_->SetBounds(insets.left(), insets.top(), kIconSize, kIconSize);
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Bottom views.
454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int bottom_y = insets.top() + std::max(top_height, kIconSize);
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int bottom_height = bottom_view_->GetHeightForWidth(content_width);
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bottom_view_->SetBounds(insets.left(), bottom_y,
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          content_width, bottom_height);
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
46090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void NotificationView::OnFocus() {
46190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MessageView::OnFocus();
46290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ScrollRectToVisible(GetLocalBounds());
46390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
46490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void NotificationView::ScrollRectToVisible(const gfx::Rect& rect) {
466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Notification want to show the whole notification when a part of it (like
467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // a button) gets focused.
468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  views::View::ScrollRectToVisible(GetLocalBounds());
469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
471a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)gfx::NativeCursor NotificationView::GetCursor(const ui::MouseEvent& event) {
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!clickable_ || !controller_->HasClickedListener(notification_id()))
47390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return views::View::GetCursor(event);
47490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
475cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return views::GetNativeHandCursor();
476a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
477a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
4780de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void NotificationView::UpdateWithNotification(
4790de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    const Notification& notification) {
4800de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  MessageView::UpdateWithNotification(notification);
4810de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
4820de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  CreateOrUpdateViews(notification);
4830de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  SetAccessibleName(notification);
4840de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  Layout();
4850de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  SchedulePaint();
4860de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
4870de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NotificationView::ButtonPressed(views::Button* sender,
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     const ui::Event& event) {
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Certain operations can cause |this| to be destructed, so copy the members
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // we send to other parts of the code.
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(dewittj): Remove this hack.
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string id(notification_id());
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // See if the button pressed was an action button.
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < action_buttons_.size(); ++i) {
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (sender == action_buttons_[i]) {
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      controller_->ClickOnNotificationButton(id, i);
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
50290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Let the superclass handled anything other than action buttons.
50390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Warning: This may cause the NotificationView itself to be deleted,
50490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // so don't do anything afterwards.
50590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MessageView::ButtonPressed(sender, event);
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void NotificationView::ClickOnNotification(const std::string& notification_id) {
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  controller_->ClickOnNotification(notification_id);
510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void NotificationView::RemoveNotification(const std::string& notification_id,
5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          bool by_user) {
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  controller_->RemoveNotification(notification_id, by_user);
515c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
516c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5170de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void NotificationView::CreateOrUpdateTitleView(
5180de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    const Notification& notification) {
5190de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (notification.title().empty()) {
5200de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    if (title_view_) {
5210de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      // Deletion will also remove |title_view_| from its parent.
5220de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      delete title_view_;
5230de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      title_view_ = NULL;
5240de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    }
5250de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    return;
5260de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
5270de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5280de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  DCHECK(top_view_ != NULL);
5290de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5300de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  const gfx::FontList& font_list =
5310de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      views::Label().font_list().DeriveWithSizeDelta(2);
5320de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5330de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  int title_character_limit =
5340de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      kNotificationWidth * kMaxTitleLines / kMinPixelsPerTitleCharacter;
5350de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::string16 title = gfx::TruncateString(notification.title(),
5375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                             title_character_limit,
5385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                             gfx::WORD_BREAK);
5390de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (!title_view_) {
5400de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    int padding = kTitleLineHeight - font_list.GetHeight();
5410de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    title_view_ = new BoundedLabel(title, font_list);
5430de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    title_view_->SetLineHeight(kTitleLineHeight);
5440de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    title_view_->SetLineLimit(kMaxTitleLines);
5450de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    title_view_->SetColors(message_center::kRegularTextColor,
5460de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                           kRegularTextBackgroundColor);
5470de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    title_view_->SetBorder(MakeTextBorder(padding, 3, 0));
5480de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    top_view_->AddChildView(title_view_);
5490de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  } else {
5505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    title_view_->SetText(title);
5510de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
5520de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
5530de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5540de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void NotificationView::CreateOrUpdateMessageView(
5550de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    const Notification& notification) {
5560de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (notification.message().empty()) {
5570de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    if (message_view_) {
5580de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      // Deletion will also remove |message_view_| from its parent.
5590de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      delete message_view_;
5600de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      message_view_ = NULL;
5610de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    }
5620de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    return;
5630de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
5640de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5650de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  DCHECK(top_view_ != NULL);
5660de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::string16 text = gfx::TruncateString(notification.message(),
5685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                            kMessageCharacterLimit,
5695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                            gfx::WORD_BREAK);
5700de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (!message_view_) {
5710de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    int padding = kMessageLineHeight - views::Label().font_list().GetHeight();
5725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    message_view_ = new BoundedLabel(text);
5730de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    message_view_->SetLineHeight(kMessageLineHeight);
5740de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    message_view_->SetColors(message_center::kRegularTextColor,
5750de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                             kDimTextBackgroundColor);
5760de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    message_view_->SetBorder(MakeTextBorder(padding, 4, 0));
5770de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    top_view_->AddChildView(message_view_);
5780de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  } else {
5795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    message_view_->SetText(text);
5800de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
5810de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5820de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  message_view_->SetVisible(!notification.items().size());
5830de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
5840de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5850de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void NotificationView::CreateOrUpdateContextMessageView(
5860de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    const Notification& notification) {
5870de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (notification.context_message().empty()) {
5880de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    if (context_message_view_) {
5890de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      // Deletion will also remove |context_message_view_| from its parent.
5900de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      delete context_message_view_;
5910de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      context_message_view_ = NULL;
5920de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    }
5930de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    return;
5940de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
5950de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5960de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  DCHECK(top_view_ != NULL);
5970de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
5985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::string16 text = gfx::TruncateString(notification.context_message(),
5995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                            kContextMessageCharacterLimit,
6005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                            gfx::WORD_BREAK);
6010de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (!context_message_view_) {
6020de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    int padding = kMessageLineHeight - views::Label().font_list().GetHeight();
6035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    context_message_view_ = new BoundedLabel(text);
6040de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    context_message_view_->SetLineLimit(
6050de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)        message_center::kContextMessageLineLimit);
6060de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    context_message_view_->SetLineHeight(kMessageLineHeight);
6070de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    context_message_view_->SetColors(message_center::kDimTextColor,
6080de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                                     kContextTextBackgroundColor);
6090de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    context_message_view_->SetBorder(MakeTextBorder(padding, 4, 0));
6100de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    top_view_->AddChildView(context_message_view_);
6110de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  } else {
6125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    context_message_view_->SetText(text);
6130de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
6140de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
6150de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6160de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void NotificationView::CreateOrUpdateProgressBarView(
6170de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    const Notification& notification) {
6180de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (notification.type() != NOTIFICATION_TYPE_PROGRESS) {
6190de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    if (progress_bar_view_) {
6200de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      // Deletion will also remove |progress_bar_view_| from its parent.
6210de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      delete progress_bar_view_;
6220de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      progress_bar_view_ = NULL;
6230de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    }
6240de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    return;
6250de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
6260de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6270de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  DCHECK(top_view_ != NULL);
6280de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6290de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (!progress_bar_view_) {
6300de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    progress_bar_view_ = new NotificationProgressBar();
6310de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    progress_bar_view_->SetBorder(MakeProgressBarBorder(
6320de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)        message_center::kProgressBarTopPadding, kProgressBarBottomPadding));
6330de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    top_view_->AddChildView(progress_bar_view_);
6340de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
6350de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6360de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  progress_bar_view_->SetValue(notification.progress() / 100.0);
6370de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  progress_bar_view_->SetVisible(!notification.items().size());
6380de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
6390de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6400de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void NotificationView::CreateOrUpdateListItemViews(
6410de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    const Notification& notification) {
6420de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  for (size_t i = 0; i < item_views_.size(); ++i)
6430de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    delete item_views_[i];
6440de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  item_views_.clear();
6450de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6460de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  int padding = kMessageLineHeight - views::Label().font_list().GetHeight();
6470de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  std::vector<NotificationItem> items = notification.items();
6480de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6490de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (items.size() == 0)
6500de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    return;
6510de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6520de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  DCHECK(top_view_);
6530de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  for (size_t i = 0; i < items.size() && i < kNotificationMaximumItems; ++i) {
6540de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    ItemView* item_view = new ItemView(items[i]);
6550de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    item_view->SetBorder(MakeTextBorder(padding, i ? 0 : 4, 0));
6560de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    item_views_.push_back(item_view);
6570de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    top_view_->AddChildView(item_view);
6580de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
6590de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
6600de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6610de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void NotificationView::CreateOrUpdateIconView(
6620de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    const Notification& notification) {
6630de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (icon_view_) {
6640de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    delete icon_view_;
6650de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    icon_view_ = NULL;
6660de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
6670de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6680de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  // TODO(dewittj): Detect a compatible update and use the existing icon view.
6690de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  gfx::ImageSkia icon = notification.icon().AsImageSkia();
6700de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (notification.type() == NOTIFICATION_TYPE_SIMPLE &&
6710de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      (icon.width() != kIconSize || icon.height() != kIconSize ||
6720de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)       HasAlpha(icon, GetWidget()))) {
6730de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    views::ImageView* icon_view = new views::ImageView();
6740de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    icon_view->SetImage(icon);
6750de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    icon_view->SetImageSize(gfx::Size(kLegacyIconSize, kLegacyIconSize));
6760de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    icon_view->SetHorizontalAlignment(views::ImageView::CENTER);
6770de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    icon_view->SetVerticalAlignment(views::ImageView::CENTER);
6780de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    icon_view_ = icon_view;
6790de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  } else {
6800de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    icon_view_ =
6810de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)        new ProportionalImageView(icon, gfx::Size(kIconSize, kIconSize));
6820de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
6830de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6840de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  icon_view_->set_background(
6850de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)      views::Background::CreateSolidBackground(kIconBackgroundColor));
6860de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6870de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  AddChildView(icon_view_);
6880de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
6890de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6900de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void NotificationView::CreateOrUpdateImageView(
6910de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    const Notification& notification) {
6920de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (image_view_) {
6930de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    delete image_view_;
6940de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    image_view_ = NULL;
6950de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
6960de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
6970de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  DCHECK(bottom_view_);
6980de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  DCHECK_EQ(this, bottom_view_->parent());
6990de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
7000de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  // TODO(dewittj): Detect a compatible update and use the existing image view.
7010de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (!notification.image().IsEmpty()) {
7020de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    gfx::Size image_size(kNotificationPreferredImageWidth,
7030de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                         kNotificationPreferredImageHeight);
7040de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    image_view_ = MakeNotificationImage(notification.image(), image_size);
70546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    bottom_view_->AddChildViewAt(image_view_, 0);
7060de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
7070de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
7080de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
7090de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)void NotificationView::CreateOrUpdateActionButtonViews(
7100de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    const Notification& notification) {
711cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<ButtonInfo> buttons = notification.buttons();
712cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool new_buttons = action_buttons_.size() != buttons.size();
7130de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
714cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (new_buttons || buttons.size() == 0) {
715cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // STLDeleteElements also clears the container.
716cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    STLDeleteElements(&separators_);
717cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    STLDeleteElements(&action_buttons_);
718cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
7190de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
7200de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  DCHECK(bottom_view_);
7210de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  DCHECK_EQ(this, bottom_view_->parent());
7220de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
7230de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  for (size_t i = 0; i < buttons.size(); ++i) {
7240de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    ButtonInfo button_info = buttons[i];
725cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (new_buttons) {
726cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      views::View* separator = new views::ImageView();
727cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      separator->SetBorder(MakeSeparatorBorder(1, 0, kButtonSeparatorColor));
728cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      separators_.push_back(separator);
729cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      bottom_view_->AddChildView(separator);
730cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      NotificationButton* button = new NotificationButton(this);
731cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      button->SetTitle(button_info.title);
732cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      button->SetIcon(button_info.icon.AsImageSkia());
733cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      action_buttons_.push_back(button);
734cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      bottom_view_->AddChildView(button);
735cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
736cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      action_buttons_[i]->SetTitle(button_info.title);
737cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      action_buttons_[i]->SetIcon(button_info.icon.AsImageSkia());
738cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      action_buttons_[i]->SchedulePaint();
739cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      action_buttons_[i]->Layout();
740cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
741cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
742cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
743cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (new_buttons) {
744cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Layout();
745cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    views::Widget* widget = GetWidget();
746cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (widget != NULL) {
747cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      widget->SetSize(widget->GetContentsView()->GetPreferredSize());
748cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      GetWidget()->SynthesizeMouseMoveEvent();
749cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
7500de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
7510de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)}
7520de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
753cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int NotificationView::GetMessageLineLimit(int title_lines, int width) const {
7545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Image notifications require that the image must be kept flush against
7555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // their icons, but we can allow more text if no image.
756010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  int effective_title_lines = std::max(0, title_lines - 1);
757010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  int line_reduction_from_title = (image_view_ ? 1 : 2) * effective_title_lines;
758010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!image_view_) {
759010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Title lines are counted as twice as big as message lines for the purpose
760010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // of this calculation.
761010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // The effect from the title reduction here should be:
762010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    //   * 0 title lines: 5 max lines message.
763010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    //   * 1 title line:  5 max lines message.
764010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    //   * 2 title lines: 3 max lines message.
765010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return std::max(
766010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        0,
767010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        message_center::kMessageExpandedLineLimit - line_reduction_from_title);
768010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
769c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
770f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  int message_line_limit = message_center::kMessageCollapsedLineLimit;
771f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
772f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Subtract any lines taken by the context message.
773f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (context_message_view_) {
774f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    message_line_limit -= context_message_view_->GetLinesForWidthAndLimit(
775f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        width,
776f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        message_center::kContextMessageLineLimit);
777c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
778c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
779010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The effect from the title reduction here should be:
780010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  //   * 0 title lines: 2 max lines message + context message.
781010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  //   * 1 title line:  2 max lines message + context message.
782010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  //   * 2 title lines: 1 max lines message + context message.
783010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  message_line_limit =
784010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      std::max(0, message_line_limit - line_reduction_from_title);
785010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
786f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return message_line_limit;
787c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
788c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
789cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int NotificationView::GetMessageHeight(int width, int limit) const {
790c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return message_view_ ?
791c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         message_view_->GetSizeForWidthAndLines(width, limit).height() : 0;
7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace message_center
795