OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/message_center/notification_view.h" | 5 #include "ui/message_center/notification_view.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
9 #include "grit/ui_resources.h" | 9 #include "grit/ui_resources.h" |
10 #include "ui/base/accessibility/accessible_view_state.h" | 10 #include "ui/base/accessibility/accessible_view_state.h" |
11 #include "ui/base/resource/resource_bundle.h" | 11 #include "ui/base/resource/resource_bundle.h" |
12 #include "ui/base/text/text_elider.h" | 12 #include "ui/base/text/text_elider.h" |
13 #include "ui/gfx/size.h" | 13 #include "ui/gfx/size.h" |
14 #include "ui/message_center/message_center_constants.h" | 14 #include "ui/message_center/message_center_constants.h" |
15 #include "ui/message_center/message_center_switches.h" | 15 #include "ui/message_center/message_center_switches.h" |
16 #include "ui/message_center/message_simple_view.h" | 16 #include "ui/message_center/message_simple_view.h" |
| 17 #include "ui/message_center/notification.h" |
| 18 #include "ui/message_center/notification_types.h" |
17 #include "ui/native_theme/native_theme.h" | 19 #include "ui/native_theme/native_theme.h" |
18 #include "ui/views/controls/button/image_button.h" | 20 #include "ui/views/controls/button/image_button.h" |
19 #include "ui/views/controls/image_view.h" | 21 #include "ui/views/controls/image_view.h" |
20 #include "ui/views/controls/label.h" | 22 #include "ui/views/controls/label.h" |
21 #include "ui/views/layout/box_layout.h" | 23 #include "ui/views/layout/box_layout.h" |
22 #include "ui/views/layout/fill_layout.h" | 24 #include "ui/views/layout/fill_layout.h" |
23 #include "ui/views/layout/grid_layout.h" | 25 #include "ui/views/layout/grid_layout.h" |
24 | 26 |
25 namespace { | 27 namespace { |
26 | 28 |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 | 194 |
193 namespace message_center { | 195 namespace message_center { |
194 | 196 |
195 // static | 197 // static |
196 MessageView* NotificationView::ViewForNotification( | 198 MessageView* NotificationView::ViewForNotification( |
197 const Notification& notification, | 199 const Notification& notification, |
198 NotificationList::Delegate* list_delegate) { | 200 NotificationList::Delegate* list_delegate) { |
199 // For the time being, use MessageSimpleView for simple notifications unless | 201 // For the time being, use MessageSimpleView for simple notifications unless |
200 // one of the use-the-new-style flags are set. This preserves the appearance | 202 // one of the use-the-new-style flags are set. This preserves the appearance |
201 // of notifications created by existing code that uses webkitNotifications. | 203 // of notifications created by existing code that uses webkitNotifications. |
202 if (notification.type == ui::notifications::NOTIFICATION_TYPE_SIMPLE && | 204 if (notification.type() == NOTIFICATION_TYPE_SIMPLE && |
203 !CommandLine::ForCurrentProcess()->HasSwitch( | 205 !CommandLine::ForCurrentProcess()->HasSwitch( |
204 message_center::switches::kEnableRichNotifications) && | 206 message_center::switches::kEnableRichNotifications) && |
205 !CommandLine::ForCurrentProcess()->HasSwitch( | 207 !CommandLine::ForCurrentProcess()->HasSwitch( |
206 message_center::switches::kEnableNewSimpleNotifications)) { | 208 message_center::switches::kEnableNewSimpleNotifications)) { |
207 return new MessageSimpleView(list_delegate, notification); | 209 return new MessageSimpleView(list_delegate, notification); |
208 } | 210 } |
209 | 211 |
210 switch (notification.type) { | 212 switch (notification.type()) { |
211 case ui::notifications::NOTIFICATION_TYPE_BASE_FORMAT: | 213 case NOTIFICATION_TYPE_BASE_FORMAT: |
212 case ui::notifications::NOTIFICATION_TYPE_IMAGE: | 214 case NOTIFICATION_TYPE_IMAGE: |
213 case ui::notifications::NOTIFICATION_TYPE_MULTIPLE: | 215 case NOTIFICATION_TYPE_MULTIPLE: |
214 case ui::notifications::NOTIFICATION_TYPE_SIMPLE: | 216 case NOTIFICATION_TYPE_SIMPLE: |
215 break; | 217 break; |
216 default: | 218 default: |
217 // If the caller asks for an unrecognized kind of view (entirely possible | 219 // If the caller asks for an unrecognized kind of view (entirely possible |
218 // if an application is running on an older version of this code that | 220 // if an application is running on an older version of this code that |
219 // doesn't have the requested kind of notification template), we'll fall | 221 // doesn't have the requested kind of notification template), we'll fall |
220 // back to a notification instance that will provide at least basic | 222 // back to a notification instance that will provide at least basic |
221 // functionality. | 223 // functionality. |
222 LOG(WARNING) << "Unable to fulfill request for unrecognized " | 224 LOG(WARNING) << "Unable to fulfill request for unrecognized " |
223 << "notification type " << notification.type << ". " | 225 << "notification type " << notification.type() << ". " |
224 << "Falling back to simple notification type."; | 226 << "Falling back to simple notification type."; |
225 } | 227 } |
226 | 228 |
227 // Currently all roads lead to the generic NotificationView. | 229 // Currently all roads lead to the generic NotificationView. |
228 return new NotificationView(list_delegate, notification); | 230 return new NotificationView(list_delegate, notification); |
229 } | 231 } |
230 | 232 |
231 NotificationView::NotificationView( | 233 NotificationView::NotificationView(NotificationList::Delegate* list_delegate, |
232 NotificationList::Delegate* list_delegate, | 234 const Notification& notification) |
233 const Notification& notification) | |
234 : MessageView(list_delegate, notification) { | 235 : MessageView(list_delegate, notification) { |
| 236 // This view is composed of two layers: The first layer has the notification |
| 237 // content (text, images, action buttons, ...). This is overlaid by a second |
| 238 // layer that has the notification close button and will later also have the |
| 239 // expand button. This allows the close and expand buttons to overlap the |
| 240 // content as needed to provide a large enough click area |
| 241 // (<http://crbug.com/168822> and touch area <http://crbug.com/168856>). |
| 242 AddChildView(MakeContentView(notification)); |
| 243 AddChildView(close_button()); |
235 } | 244 } |
236 | 245 |
237 NotificationView::~NotificationView() { | 246 NotificationView::~NotificationView() { |
238 } | 247 } |
239 | 248 |
240 void NotificationView::Layout() { | 249 void NotificationView::Layout() { |
241 if (content_view_) { | 250 if (content_view_) { |
242 gfx::Rect contents_bounds = GetContentsBounds(); | 251 gfx::Rect contents_bounds = GetContentsBounds(); |
243 content_view_->SetBoundsRect(contents_bounds); | 252 content_view_->SetBoundsRect(contents_bounds); |
244 if (close_button()) { | 253 if (close_button()) { |
245 gfx::Size size(close_button()->GetPreferredSize()); | 254 gfx::Size size(close_button()->GetPreferredSize()); |
246 close_button()->SetBounds(contents_bounds.right() - size.width(), 0, | 255 close_button()->SetBounds(contents_bounds.right() - size.width(), 0, |
247 size.width(), size.height()); | 256 size.width(), size.height()); |
248 } | 257 } |
249 } | 258 } |
250 } | 259 } |
251 | 260 |
252 gfx::Size NotificationView::GetPreferredSize() { | 261 gfx::Size NotificationView::GetPreferredSize() { |
253 if (!content_view_) | 262 if (!content_view_) |
254 return gfx::Size(); | 263 return gfx::Size(); |
255 gfx::Size size = content_view_->GetPreferredSize(); | 264 gfx::Size size = content_view_->GetPreferredSize(); |
256 if (border()) { | 265 if (border()) { |
257 gfx::Insets border_insets = border()->GetInsets(); | 266 gfx::Insets border_insets = border()->GetInsets(); |
258 size.Enlarge(border_insets.width(), border_insets.height()); | 267 size.Enlarge(border_insets.width(), border_insets.height()); |
259 } | 268 } |
260 return size; | 269 return size; |
261 } | 270 } |
262 | 271 |
263 void NotificationView::SetUpView() { | |
264 // This view is composed of two layers: The first layer has the notification | |
265 // content (text, images, action buttons, ...). This is overlaid by a second | |
266 // layer that has the notification close button and will later also have the | |
267 // expand button. This allows the close and expand buttons to overlap the | |
268 // content as needed to provide a large enough click area | |
269 // (<http://crbug.com/168822> and touch area <http://crbug.com/168856>). | |
270 AddChildView(MakeContentView()); | |
271 AddChildView(close_button()); | |
272 } | |
273 | |
274 void NotificationView::ButtonPressed(views::Button* sender, | 272 void NotificationView::ButtonPressed(views::Button* sender, |
275 const ui::Event& event) { | 273 const ui::Event& event) { |
276 for (size_t i = 0; i < action_buttons_.size(); ++i) { | 274 for (size_t i = 0; i < action_buttons_.size(); ++i) { |
277 if (action_buttons_[i] == sender) { | 275 if (action_buttons_[i] == sender) { |
278 list_delegate()->OnButtonClicked(notification().id, i); | 276 list_delegate()->OnButtonClicked(notification_id(), i); |
279 return; | 277 return; |
280 } | 278 } |
281 } | 279 } |
282 MessageView::ButtonPressed(sender, event); | 280 MessageView::ButtonPressed(sender, event); |
283 } | 281 } |
284 | 282 |
285 views::View* NotificationView::MakeContentView() { | 283 views::View* NotificationView::MakeContentView( |
| 284 const Notification& notification) { |
286 content_view_ = new views::View(); | 285 content_view_ = new views::View(); |
287 content_view_->set_background( | 286 content_view_->set_background( |
288 views::Background::CreateSolidBackground(kBackgroundColor)); | 287 views::Background::CreateSolidBackground(kBackgroundColor)); |
289 | 288 |
290 // The top part of the content view is composed of an icon view on the left | 289 // The top part of the content view is composed of an icon view on the left |
291 // and a certain number of text views on the right (title and message or list | 290 // and a certain number of text views on the right (title and message or list |
292 // items), followed by a padding view. Laying out the icon view will require | 291 // items), followed by a padding view. Laying out the icon view will require |
293 // information about the text views, so these are created first and collected | 292 // information about the text views, so these are created first and collected |
294 // in this vector. | 293 // in this vector. |
295 std::vector<views::View*> texts; | 294 std::vector<views::View*> texts; |
296 | 295 |
297 // Title if it exists. | 296 // Title if it exists. |
298 if (!notification().title.empty()) { | 297 if (!notification.title().empty()) { |
299 views::Label* title = new views::Label(notification().title); | 298 views::Label* title = new views::Label(notification.title()); |
300 title->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 299 title->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
301 title->SetElideBehavior(views::Label::ELIDE_AT_END); | 300 title->SetElideBehavior(views::Label::ELIDE_AT_END); |
302 title->SetFont(title->font().DeriveFont(4)); | 301 title->SetFont(title->font().DeriveFont(4)); |
303 title->SetEnabledColor(kTitleColor); | 302 title->SetEnabledColor(kTitleColor); |
304 title->SetBackgroundColor(kTitleBackgroundColor); | 303 title->SetBackgroundColor(kTitleBackgroundColor); |
305 title->set_border(MakePadding(kTextTopPadding, 0, 3, kTextRightPadding)); | 304 title->set_border(MakePadding(kTextTopPadding, 0, 3, kTextRightPadding)); |
306 texts.push_back(title); | 305 texts.push_back(title); |
307 } | 306 } |
308 | 307 |
309 // Message if appropriate. | 308 // Message if appropriate. |
310 if (notification().items.size() == 0 && !notification().message.empty()) { | 309 if (notification.items().size() == 0 && |
311 views::Label* message = new views::Label(notification().message); | 310 !notification.message().empty()) { |
| 311 views::Label* message = new views::Label(notification.message()); |
312 message->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 312 message->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
313 message->SetMultiLine(true); | 313 message->SetMultiLine(true); |
314 message->SetEnabledColor(kMessageColor); | 314 message->SetEnabledColor(kMessageColor); |
315 message->SetBackgroundColor(kMessageBackgroundColor); | 315 message->SetBackgroundColor(kMessageBackgroundColor); |
316 message->set_border(MakePadding(0, 0, 3, kTextRightPadding)); | 316 message->set_border(MakePadding(0, 0, 3, kTextRightPadding)); |
317 texts.push_back(message); | 317 texts.push_back(message); |
318 } | 318 } |
319 | 319 |
320 // List notification items up to a maximum. | 320 // List notification items up to a maximum. |
321 int items = std::min(notification().items.size(), kNotificationMaximumItems); | 321 int items = std::min(notification.items().size(), |
| 322 kNotificationMaximumItems); |
322 for (int i = 0; i < items; ++i) { | 323 for (int i = 0; i < items; ++i) { |
323 ItemView* item = new ItemView(notification().items[i]); | 324 ItemView* item = new ItemView(notification.items()[i]); |
324 item->set_border(MakePadding(0, 0, 4, kTextRightPadding)); | 325 item->set_border(MakePadding(0, 0, 4, kTextRightPadding)); |
325 texts.push_back(item); | 326 texts.push_back(item); |
326 } | 327 } |
327 | 328 |
328 // Set up the content view with a fixed-width icon column on the left and a | 329 // Set up the content view with a fixed-width icon column on the left and a |
329 // text column on the right that consumes the remaining space. To minimize the | 330 // text column on the right that consumes the remaining space. To minimize the |
330 // number of columns and simplify column spanning, padding is applied to each | 331 // number of columns and simplify column spanning, padding is applied to each |
331 // view within columns instead of through padding columns. | 332 // view within columns instead of through padding columns. |
332 views::GridLayout* layout = new views::GridLayout(content_view_); | 333 views::GridLayout* layout = new views::GridLayout(content_view_); |
333 content_view_->SetLayoutManager(layout); | 334 content_view_->SetLayoutManager(layout); |
334 views::ColumnSet* columns = layout->AddColumnSet(0); | 335 views::ColumnSet* columns = layout->AddColumnSet(0); |
335 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, | 336 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, |
336 0, views::GridLayout::FIXED, | 337 0, views::GridLayout::FIXED, |
337 kIconColumnWidth + kIconToTextPadding, | 338 kIconColumnWidth + kIconToTextPadding, |
338 kIconColumnWidth + kIconToTextPadding); | 339 kIconColumnWidth + kIconToTextPadding); |
339 // Padding + icon + padding. | 340 // Padding + icon + padding. |
340 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, | 341 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, |
341 100, views::GridLayout::USE_PREF, 0, 0); | 342 100, views::GridLayout::USE_PREF, 0, 0); |
342 // Text + padding. | 343 // Text + padding. |
343 | 344 |
344 // Create the first row and its icon view, which spans all the text views | 345 // Create the first row and its icon view, which spans all the text views |
345 // to its right as well as the padding view below them. | 346 // to its right as well as the padding view below them. |
346 layout->StartRow(0, 0); | 347 layout->StartRow(0, 0); |
347 views::ImageView* icon = new views::ImageView(); | 348 views::ImageView* icon = new views::ImageView(); |
348 icon->SetImageSize(gfx::Size(message_center::kNotificationIconSize, | 349 icon->SetImageSize(gfx::Size(message_center::kNotificationIconSize, |
349 message_center::kNotificationIconSize)); | 350 message_center::kNotificationIconSize)); |
350 icon->SetImage(notification().primary_icon); | 351 icon->SetImage(notification.primary_icon()); |
351 icon->SetHorizontalAlignment(views::ImageView::LEADING); | 352 icon->SetHorizontalAlignment(views::ImageView::LEADING); |
352 icon->SetVerticalAlignment(views::ImageView::LEADING); | 353 icon->SetVerticalAlignment(views::ImageView::LEADING); |
353 icon->set_border(MakePadding(0, 0, 0, kIconToTextPadding)); | 354 icon->set_border(MakePadding(0, 0, 0, kIconToTextPadding)); |
354 layout->AddView(icon, 1, texts.size() + 1); | 355 layout->AddView(icon, 1, texts.size() + 1); |
355 | 356 |
356 // Add the text views, creating rows for them if necessary. | 357 // Add the text views, creating rows for them if necessary. |
357 for (size_t i = 0; i < texts.size(); ++i) { | 358 for (size_t i = 0; i < texts.size(); ++i) { |
358 if (i > 0) { | 359 if (i > 0) { |
359 layout->StartRow(0, 0); | 360 layout->StartRow(0, 0); |
360 layout->SkipColumns(1); | 361 layout->SkipColumns(1); |
361 } | 362 } |
362 layout->AddView(texts[i]); | 363 layout->AddView(texts[i]); |
363 } | 364 } |
364 | 365 |
365 // Add a text padding row if necessary. This adds some space between the last | 366 // Add a text padding row if necessary. This adds some space between the last |
366 // line of text and anything below it but it also ensures views above it are | 367 // line of text and anything below it but it also ensures views above it are |
367 // top-justified by expanding vertically to take up any extra space. | 368 // top-justified by expanding vertically to take up any extra space. |
368 if (texts.size() == 0) { | 369 if (texts.size() == 0) { |
369 layout->SkipColumns(1); | 370 layout->SkipColumns(1); |
370 } else { | 371 } else { |
371 layout->StartRow(100, 0); | 372 layout->StartRow(100, 0); |
372 layout->SkipColumns(1); | 373 layout->SkipColumns(1); |
373 views::View* padding = new views::ImageView(); | 374 views::View* padding = new views::ImageView(); |
374 padding->set_border(MakePadding(kTextBottomPadding, 1, 0, 0)); | 375 padding->set_border(MakePadding(kTextBottomPadding, 1, 0, 0)); |
375 layout->AddView(padding); | 376 layout->AddView(padding); |
376 } | 377 } |
377 | 378 |
378 // Add an image row if appropriate. | 379 // Add an image row if appropriate. |
379 if (!notification().image.isNull()) { | 380 if (!notification.image().isNull()) { |
380 layout->StartRow(0, 0); | 381 layout->StartRow(0, 0); |
381 views::ImageView* image = new ProportionalImageView(); | 382 views::ImageView* image = new ProportionalImageView(); |
382 image->SetImageSize(notification().image.size()); | 383 image->SetImageSize(notification.image().size()); |
383 image->SetImage(notification().image); | 384 image->SetImage(notification.image()); |
384 image->SetHorizontalAlignment(views::ImageView::CENTER); | 385 image->SetHorizontalAlignment(views::ImageView::CENTER); |
385 image->SetVerticalAlignment(views::ImageView::LEADING); | 386 image->SetVerticalAlignment(views::ImageView::LEADING); |
386 layout->AddView(image, 2, 1); | 387 layout->AddView(image, 2, 1); |
387 } | 388 } |
388 | 389 |
389 // Add action button rows. | 390 // Add action button rows. |
390 for (size_t i = 0; i < notification().button_titles.size(); ++i) { | 391 for (size_t i = 0; i < notification.buttons().size(); ++i) { |
391 views::View* separator = new views::View(); | 392 views::View* separator = new views::View(); |
392 separator->set_background(MakeBackground(kButtonSeparatorColor)); | 393 separator->set_background(MakeBackground(kButtonSeparatorColor)); |
393 layout->StartRow(0, 0); | 394 layout->StartRow(0, 0); |
394 layout->AddView(separator, 2, 1, | 395 layout->AddView(separator, 2, 1, |
395 views::GridLayout::FILL, views::GridLayout::FILL, 0, 1); | 396 views::GridLayout::FILL, views::GridLayout::FILL, 0, 1); |
396 NotificationButton* button = new NotificationButton(this); | 397 NotificationButton* button = new NotificationButton(this); |
397 button->SetTitle(notification().button_titles[i]); | 398 ButtonInfo button_info = notification.buttons()[i]; |
398 button->SetIcon(notification().button_icons[i]); | 399 button->SetTitle(button_info.title); |
| 400 button->SetIcon(button_info.icon); |
399 action_buttons_.push_back(button); | 401 action_buttons_.push_back(button); |
400 layout->StartRow(0, 0); | 402 layout->StartRow(0, 0); |
401 layout->AddView(button, 2, 1, | 403 layout->AddView(button, 2, 1, |
402 views::GridLayout::FILL, views::GridLayout::FILL, 0, 40); | 404 views::GridLayout::FILL, views::GridLayout::FILL, 0, 40); |
403 } | 405 } |
404 | 406 |
405 return content_view_; | 407 return content_view_; |
406 } | 408 } |
407 | 409 |
408 } // namespace message_center | 410 } // namespace message_center |
OLD | NEW |