• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ui/message_center/views/group_view.h"
6 
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "grit/ui_resources.h"
11 #include "grit/ui_strings.h"
12 #include "ui/base/l10n/l10n_util.h"
13 #include "ui/base/layout.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/canvas.h"
16 #include "ui/gfx/size.h"
17 #include "ui/gfx/skia_util.h"
18 #include "ui/gfx/text_elider.h"
19 #include "ui/message_center/message_center.h"
20 #include "ui/message_center/message_center_style.h"
21 #include "ui/message_center/message_center_tray.h"
22 #include "ui/message_center/message_center_util.h"
23 #include "ui/message_center/notification.h"
24 #include "ui/message_center/views/bounded_label.h"
25 #include "ui/message_center/views/constants.h"
26 #include "ui/message_center/views/notification_button.h"
27 #include "ui/message_center/views/proportional_image_view.h"
28 #include "ui/native_theme/native_theme.h"
29 #include "ui/views/background.h"
30 #include "ui/views/border.h"
31 #include "ui/views/controls/button/image_button.h"
32 #include "ui/views/controls/image_view.h"
33 #include "ui/views/controls/label.h"
34 #include "ui/views/layout/box_layout.h"
35 #include "ui/views/layout/fill_layout.h"
36 #include "ui/views/widget/widget.h"
37 
38 #if defined(USE_AURA)
39 #include "ui/base/cursor/cursor.h"
40 #endif
41 
42 namespace {
43 
44 // static
MakeTextBorder(int padding,int top,int bottom)45 views::Border* MakeTextBorder(int padding, int top, int bottom) {
46   // Split the padding between the top and the bottom, then add the extra space.
47   return views::Border::CreateEmptyBorder(padding / 2 + top,
48                                           message_center::kTextLeftPadding,
49                                           (padding + 1) / 2 + bottom,
50                                           message_center::kTextRightPadding);
51 }
52 
53 }  // namespace
54 
55 namespace message_center {
56 
57 // GroupView ////////////////////////////////////////////////////////////
58 
GroupView(MessageCenterController * controller,const NotifierId & notifier_id,const Notification & last_notification,const gfx::ImageSkia & group_icon,int group_size)59 GroupView::GroupView(MessageCenterController* controller,
60                      const NotifierId& notifier_id,
61                      const Notification& last_notification,
62                      const gfx::ImageSkia& group_icon,
63                      int group_size)
64     : MessageView(this,
65                   last_notification.id(),
66                   notifier_id,
67                   last_notification.display_source()),
68       controller_(controller),
69       notifier_id_(notifier_id),
70       display_source_(last_notification.display_source()),
71       group_icon_(group_icon),
72       group_size_(group_size),
73       last_notification_id_(last_notification.id()),
74       background_view_(NULL),
75       top_view_(NULL),
76       bottom_view_(NULL),
77       title_view_(NULL),
78       message_view_(NULL),
79       context_message_view_(NULL),
80       icon_view_(NULL)
81 {
82   std::vector<string16> accessible_lines;
83   // TODO (dimich): move to MessageView
84   // Create the opaque background that's above the view's shadow.
85   background_view_ = new views::View();
86   background_view_->set_background(
87       views::Background::CreateSolidBackground(
88           message_center::kNotificationBackgroundColor));
89 
90   // Create the top_view_, which collects into a vertical box all content
91   // at the top of the notification (to the right of the icon) except for the
92   // close button.
93   top_view_ = new views::View();
94   top_view_->SetLayoutManager(
95       new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
96   top_view_->set_border(views::Border::CreateEmptyBorder(
97       kTextTopPadding - 8, 0, kTextBottomPadding - 5, 0));
98 
99   const gfx::FontList default_label_font_list = views::Label().font_list();
100 
101   // Create the title view if appropriate.
102   const gfx::FontList& font_list =
103       default_label_font_list.DeriveFontListWithSizeDelta(2);
104   int padding = kTitleLineHeight - font_list.GetHeight();
105 
106   title_view_ = new BoundedLabel(
107       gfx::TruncateString(string16(last_notification.title()),
108                           kTitleCharacterLimit),
109                           font_list);
110   accessible_lines.push_back(last_notification.title());
111   title_view_->SetLineHeight(kTitleLineHeight);
112   title_view_->SetLineLimit(message_center::kTitleLineLimit);
113   title_view_->SetColors(message_center::kRegularTextColor,
114                          kRegularTextBackgroundColor);
115   title_view_->set_border(MakeTextBorder(padding, 3, 0));
116   top_view_->AddChildView(title_view_);
117 
118   // Create the message view if appropriate.
119   if (!last_notification.message().empty()) {
120     int padding = kMessageLineHeight - default_label_font_list.GetHeight();
121     message_view_ = new BoundedLabel(
122         gfx::TruncateString(last_notification.message(),
123                             kMessageCharacterLimit));
124     message_view_->SetLineHeight(kMessageLineHeight);
125     message_view_->SetColors(message_center::kRegularTextColor,
126                              kDimTextBackgroundColor);
127     message_view_->set_border(MakeTextBorder(padding, 4, 0));
128     top_view_->AddChildView(message_view_);
129     accessible_lines.push_back(last_notification.message());
130   }
131 
132   // Create the context message view if appropriate.
133   if (!last_notification.context_message().empty()) {
134     int padding = kMessageLineHeight - default_label_font_list.GetHeight();
135     context_message_view_ = new BoundedLabel(gfx::TruncateString(
136         last_notification.context_message(), kContextMessageCharacterLimit),
137         default_label_font_list);
138     context_message_view_->SetLineLimit(
139         message_center::kContextMessageLineLimit);
140     context_message_view_->SetLineHeight(kMessageLineHeight);
141     context_message_view_->SetColors(message_center::kDimTextColor,
142                                      kContextTextBackgroundColor);
143     context_message_view_->set_border(MakeTextBorder(padding, 4, 0));
144     top_view_->AddChildView(context_message_view_);
145     accessible_lines.push_back(last_notification.context_message());
146   }
147 
148   // Create the notification icon view.
149   icon_view_ =
150       new ProportionalImageView(last_notification.icon().AsImageSkia());
151   icon_view_->set_background(views::Background::CreateSolidBackground(
152       kIconBackgroundColor));
153 
154   // Create the bottom_view_, which collects into a vertical box all content
155   // below the notification icon except for the expandGroup button.
156   bottom_view_ = new views::View();
157   bottom_view_->SetLayoutManager(
158       new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
159 
160   // Create "N more.." action button
161   views::View* separator = new views::ImageView();
162   separator->set_border(views::Border::CreateSolidSidedBorder(
163       1, 0, 0, 0, kButtonSeparatorColor));
164   bottom_view_->AddChildView(separator);
165   more_button_ = new NotificationButton(this);
166   string16 button_title =
167       l10n_util::GetStringFUTF16(IDS_MESSAGE_CENTER_MORE_FROM,
168                                  base::IntToString16(group_size_),
169                                  display_source_);
170   more_button_->SetTitle(button_title);
171   more_button_->SetIcon(group_icon_);
172   bottom_view_->AddChildView(more_button_);
173 
174   // Put together the different content and control views. Layering those allows
175   // for proper layout logic and it also allows the close button to
176   // overlap the content as needed to provide large enough click and touch area.
177   AddChildView(background_view_);
178   AddChildView(top_view_);
179   AddChildView(icon_view_);
180   AddChildView(bottom_view_);
181   AddChildView(close_button());
182   set_accessible_name(JoinString(accessible_lines, '\n'));
183 }
184 
~GroupView()185 GroupView::~GroupView() {
186 }
187 
GetPreferredSize()188 gfx::Size GroupView::GetPreferredSize() {
189   int top_width = top_view_->GetPreferredSize().width();
190   int bottom_width = bottom_view_->GetPreferredSize().width();
191   int preferred_width = std::max(top_width, bottom_width) + GetInsets().width();
192   return gfx::Size(preferred_width, GetHeightForWidth(preferred_width));
193 }
194 
GetHeightForWidth(int width)195 int GroupView::GetHeightForWidth(int width) {
196   int content_width = width - GetInsets().width();
197   int top_height = top_view_->GetHeightForWidth(content_width);
198   int bottom_height = bottom_view_->GetHeightForWidth(content_width);
199   int content_height = std::max(top_height, kIconSize) + bottom_height;
200 
201   // Adjust the height to make sure there is at least 16px of space below the
202   // icon if there is any space there (<http://crbug.com/232966>).
203   if (content_height > kIconSize)
204     content_height = std::max(content_height,
205                               kIconSize + message_center::kIconBottomPadding);
206 
207   return content_height + GetInsets().height();
208 }
209 
Layout()210 void GroupView::Layout() {
211   gfx::Insets insets = GetInsets();
212   int content_width = width() - insets.width();
213   int content_right = width() - insets.right();
214 
215   // Background.
216   background_view_->SetBounds(insets.left(), insets.top(),
217                               content_width, height() - insets.height());
218 
219   // Top views.
220   int top_height = top_view_->GetHeightForWidth(content_width);
221   top_view_->SetBounds(insets.left(), insets.top(), content_width, top_height);
222 
223   // Icon.
224   icon_view_->SetBounds(insets.left(), insets.top(), kIconSize, kIconSize);
225 
226   // Bottom views.
227   int bottom_y = insets.top() + std::max(top_height, kIconSize);
228   int bottom_height = bottom_view_->GetHeightForWidth(content_width);
229   bottom_view_->SetBounds(insets.left(), bottom_y,
230                           content_width, bottom_height);
231 
232   // Close button.
233   gfx::Size close_size(close_button()->GetPreferredSize());
234   close_button()->SetBounds(content_right - close_size.width(), insets.top(),
235                             close_size.width(), close_size.height());
236 }
237 
OnFocus()238 void GroupView::OnFocus() {
239   MessageView::OnFocus();
240   ScrollRectToVisible(GetLocalBounds());
241 }
242 
GetCursor(const ui::MouseEvent & event)243 gfx::NativeCursor GroupView::GetCursor(const ui::MouseEvent& event) {
244 // If we ever have non-Aura views environment, this will fail compilation.
245 #if defined(USE_AURA)
246   return ui::kCursorHand;
247 #endif
248 }
249 
ButtonPressed(views::Button * sender,const ui::Event & event)250 void GroupView::ButtonPressed(views::Button* sender,
251                               const ui::Event& event) {
252   if (sender == more_button_) {
253     controller_->ExpandGroup(notifier_id_);
254     return;
255   }
256   // Let the superclass handle anything other than action buttons.
257   // Warning: This may cause the GroupView itself to be deleted,
258   // so don't do anything afterwards.
259   MessageView::ButtonPressed(sender, event);
260 }
261 
ClickOnNotification(const std::string & notification_id)262 void GroupView::ClickOnNotification(const std::string& notification_id) {
263   controller_->GroupBodyClicked(notification_id);
264 }
265 
RemoveNotification(const std::string & notification_id,bool by_user)266 void GroupView::RemoveNotification(const std::string& notification_id,
267                                    bool by_user) {
268   controller_->RemoveGroup(notifier_id_);
269 }
270 
DisableNotificationsFromThisSource(const NotifierId & notifier_id)271 void GroupView::DisableNotificationsFromThisSource(
272     const NotifierId& notifier_id) {
273   controller_->DisableNotificationsFromThisSource(notifier_id);
274 }
275 
ShowNotifierSettingsBubble()276 void GroupView::ShowNotifierSettingsBubble() {
277   controller_->ShowNotifierSettingsBubble();
278 }
279 
280 }  // namespace message_center
281