| 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 scoped_ptr<MessageSimpleView> result(new MessageSimpleView(list_delegate)); |
| 210 result->SetUpView(notification); |
| 211 return result.release(); |
| 208 } | 212 } |
| 209 | 213 |
| 210 switch (notification.type) { | 214 switch (notification.type()) { |
| 211 case ui::notifications::NOTIFICATION_TYPE_BASE_FORMAT: | 215 case NOTIFICATION_TYPE_BASE_FORMAT: |
| 212 case ui::notifications::NOTIFICATION_TYPE_IMAGE: | 216 case NOTIFICATION_TYPE_IMAGE: |
| 213 case ui::notifications::NOTIFICATION_TYPE_MULTIPLE: | 217 case NOTIFICATION_TYPE_MULTIPLE: |
| 214 case ui::notifications::NOTIFICATION_TYPE_SIMPLE: | 218 case NOTIFICATION_TYPE_SIMPLE: |
| 215 break; | 219 break; |
| 216 default: | 220 default: |
| 217 // If the caller asks for an unrecognized kind of view (entirely possible | 221 // 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 | 222 // 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 | 223 // doesn't have the requested kind of notification template), we'll fall |
| 220 // back to a notification instance that will provide at least basic | 224 // back to a notification instance that will provide at least basic |
| 221 // functionality. | 225 // functionality. |
| 222 LOG(WARNING) << "Unable to fulfill request for unrecognized " | 226 LOG(WARNING) << "Unable to fulfill request for unrecognized " |
| 223 << "notification type " << notification.type << ". " | 227 << "notification type " << notification.type() << ". " |
| 224 << "Falling back to simple notification type."; | 228 << "Falling back to simple notification type."; |
| 225 } | 229 } |
| 226 | 230 |
| 227 // Currently all roads lead to the generic NotificationView. | 231 // Currently all roads lead to the generic NotificationView. |
| 228 return new NotificationView(list_delegate, notification); | 232 scoped_ptr<NotificationView> result(new NotificationView(list_delegate)); |
| 233 result->SetUpView(notification); |
| 234 return result.release(); |
| 229 } | 235 } |
| 230 | 236 |
| 231 NotificationView::NotificationView( | 237 NotificationView::NotificationView(NotificationList::Delegate* list_delegate) |
| 232 NotificationList::Delegate* list_delegate, | 238 : MessageView(list_delegate) { |
| 233 const Notification& notification) | |
| 234 : MessageView(list_delegate, notification) { | |
| 235 } | 239 } |
| 236 | 240 |
| 237 NotificationView::~NotificationView() { | 241 NotificationView::~NotificationView() { |
| 238 } | 242 } |
| 239 | 243 |
| 240 void NotificationView::Layout() { | 244 void NotificationView::Layout() { |
| 241 if (content_view_) { | 245 if (content_view_) { |
| 242 gfx::Rect contents_bounds = GetContentsBounds(); | 246 gfx::Rect contents_bounds = GetContentsBounds(); |
| 243 content_view_->SetBoundsRect(contents_bounds); | 247 content_view_->SetBoundsRect(contents_bounds); |
| 244 if (close_button()) { | 248 if (close_button()) { |
| 245 gfx::Size size(close_button()->GetPreferredSize()); | 249 gfx::Size size(close_button()->GetPreferredSize()); |
| 246 close_button()->SetBounds(contents_bounds.right() - size.width(), 0, | 250 close_button()->SetBounds(contents_bounds.right() - size.width(), 0, |
| 247 size.width(), size.height()); | 251 size.width(), size.height()); |
| 248 } | 252 } |
| 249 } | 253 } |
| 250 } | 254 } |
| 251 | 255 |
| 252 gfx::Size NotificationView::GetPreferredSize() { | 256 gfx::Size NotificationView::GetPreferredSize() { |
| 253 if (!content_view_) | 257 if (!content_view_) |
| 254 return gfx::Size(); | 258 return gfx::Size(); |
| 255 gfx::Size size = content_view_->GetPreferredSize(); | 259 gfx::Size size = content_view_->GetPreferredSize(); |
| 256 if (border()) { | 260 if (border()) { |
| 257 gfx::Insets border_insets = border()->GetInsets(); | 261 gfx::Insets border_insets = border()->GetInsets(); |
| 258 size.Enlarge(border_insets.width(), border_insets.height()); | 262 size.Enlarge(border_insets.width(), border_insets.height()); |
| 259 } | 263 } |
| 260 return size; | 264 return size; |
| 261 } | 265 } |
| 262 | 266 |
| 263 void NotificationView::SetUpView() { | 267 void NotificationView::SetUpView(const Notification& notification) { |
| 268 MessageView::SetUpView(notification); |
| 264 // This view is composed of two layers: The first layer has the notification | 269 // 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 | 270 // 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 | 271 // 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 | 272 // expand button. This allows the close and expand buttons to overlap the |
| 268 // content as needed to provide a large enough click area | 273 // content as needed to provide a large enough click area |
| 269 // (<http://crbug.com/168822> and touch area <http://crbug.com/168856>). | 274 // (<http://crbug.com/168822> and touch area <http://crbug.com/168856>). |
| 270 AddChildView(MakeContentView()); | 275 AddChildView(MakeContentView(notification)); |
| 271 AddChildView(close_button()); | 276 AddChildView(close_button()); |
| 272 } | 277 } |
| 273 | 278 |
| 274 void NotificationView::ButtonPressed(views::Button* sender, | 279 void NotificationView::ButtonPressed(views::Button* sender, |
| 275 const ui::Event& event) { | 280 const ui::Event& event) { |
| 276 for (size_t i = 0; i < action_buttons_.size(); ++i) { | 281 for (size_t i = 0; i < action_buttons_.size(); ++i) { |
| 277 if (action_buttons_[i] == sender) { | 282 if (action_buttons_[i] == sender) { |
| 278 list_delegate()->OnButtonClicked(notification().id, i); | 283 list_delegate()->OnButtonClicked(notification_id(), i); |
| 279 return; | 284 return; |
| 280 } | 285 } |
| 281 } | 286 } |
| 282 MessageView::ButtonPressed(sender, event); | 287 MessageView::ButtonPressed(sender, event); |
| 283 } | 288 } |
| 284 | 289 |
| 285 views::View* NotificationView::MakeContentView() { | 290 views::View* NotificationView::MakeContentView( |
| 291 const Notification& notification) { |
| 286 content_view_ = new views::View(); | 292 content_view_ = new views::View(); |
| 287 content_view_->set_background( | 293 content_view_->set_background( |
| 288 views::Background::CreateSolidBackground(kBackgroundColor)); | 294 views::Background::CreateSolidBackground(kBackgroundColor)); |
| 289 | 295 |
| 290 // The top part of the content view is composed of an icon view on the left | 296 // 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 | 297 // 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 | 298 // 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 | 299 // information about the text views, so these are created first and collected |
| 294 // in this vector. | 300 // in this vector. |
| 295 std::vector<views::View*> texts; | 301 std::vector<views::View*> texts; |
| 296 | 302 |
| 297 // Title if it exists. | 303 // Title if it exists. |
| 298 if (!notification().title.empty()) { | 304 if (!notification.title().empty()) { |
| 299 views::Label* title = new views::Label(notification().title); | 305 views::Label* title = new views::Label(notification.title()); |
| 300 title->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 306 title->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| 301 title->SetElideBehavior(views::Label::ELIDE_AT_END); | 307 title->SetElideBehavior(views::Label::ELIDE_AT_END); |
| 302 title->SetFont(title->font().DeriveFont(4)); | 308 title->SetFont(title->font().DeriveFont(4)); |
| 303 title->SetEnabledColor(kTitleColor); | 309 title->SetEnabledColor(kTitleColor); |
| 304 title->SetBackgroundColor(kTitleBackgroundColor); | 310 title->SetBackgroundColor(kTitleBackgroundColor); |
| 305 title->set_border(MakePadding(kTextTopPadding, 0, 3, kTextRightPadding)); | 311 title->set_border(MakePadding(kTextTopPadding, 0, 3, kTextRightPadding)); |
| 306 texts.push_back(title); | 312 texts.push_back(title); |
| 307 } | 313 } |
| 308 | 314 |
| 309 // Message if appropriate. | 315 // Message if appropriate. |
| 310 if (notification().items.size() == 0 && !notification().message.empty()) { | 316 if (notification.items().size() == 0 && |
| 311 views::Label* message = new views::Label(notification().message); | 317 !notification.message().empty()) { |
| 318 views::Label* message = new views::Label(notification.message()); |
| 312 message->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 319 message->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| 313 message->SetMultiLine(true); | 320 message->SetMultiLine(true); |
| 314 message->SetEnabledColor(kMessageColor); | 321 message->SetEnabledColor(kMessageColor); |
| 315 message->SetBackgroundColor(kMessageBackgroundColor); | 322 message->SetBackgroundColor(kMessageBackgroundColor); |
| 316 message->set_border(MakePadding(0, 0, 3, kTextRightPadding)); | 323 message->set_border(MakePadding(0, 0, 3, kTextRightPadding)); |
| 317 texts.push_back(message); | 324 texts.push_back(message); |
| 318 } | 325 } |
| 319 | 326 |
| 320 // List notification items up to a maximum. | 327 // List notification items up to a maximum. |
| 321 int items = std::min(notification().items.size(), kNotificationMaximumItems); | 328 int items = std::min(notification.items().size(), |
| 329 kNotificationMaximumItems); |
| 322 for (int i = 0; i < items; ++i) { | 330 for (int i = 0; i < items; ++i) { |
| 323 ItemView* item = new ItemView(notification().items[i]); | 331 ItemView* item = new ItemView(notification.items()[i]); |
| 324 item->set_border(MakePadding(0, 0, 4, kTextRightPadding)); | 332 item->set_border(MakePadding(0, 0, 4, kTextRightPadding)); |
| 325 texts.push_back(item); | 333 texts.push_back(item); |
| 326 } | 334 } |
| 327 | 335 |
| 328 // Set up the content view with a fixed-width icon column on the left and a | 336 // 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 | 337 // 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 | 338 // number of columns and simplify column spanning, padding is applied to each |
| 331 // view within columns instead of through padding columns. | 339 // view within columns instead of through padding columns. |
| 332 views::GridLayout* layout = new views::GridLayout(content_view_); | 340 views::GridLayout* layout = new views::GridLayout(content_view_); |
| 333 content_view_->SetLayoutManager(layout); | 341 content_view_->SetLayoutManager(layout); |
| 334 views::ColumnSet* columns = layout->AddColumnSet(0); | 342 views::ColumnSet* columns = layout->AddColumnSet(0); |
| 335 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, | 343 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, |
| 336 0, views::GridLayout::FIXED, | 344 0, views::GridLayout::FIXED, |
| 337 kIconColumnWidth + kIconToTextPadding, | 345 kIconColumnWidth + kIconToTextPadding, |
| 338 kIconColumnWidth + kIconToTextPadding); | 346 kIconColumnWidth + kIconToTextPadding); |
| 339 // Padding + icon + padding. | 347 // Padding + icon + padding. |
| 340 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, | 348 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, |
| 341 100, views::GridLayout::USE_PREF, 0, 0); | 349 100, views::GridLayout::USE_PREF, 0, 0); |
| 342 // Text + padding. | 350 // Text + padding. |
| 343 | 351 |
| 344 // Create the first row and its icon view, which spans all the text views | 352 // 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. | 353 // to its right as well as the padding view below them. |
| 346 layout->StartRow(0, 0); | 354 layout->StartRow(0, 0); |
| 347 views::ImageView* icon = new views::ImageView(); | 355 views::ImageView* icon = new views::ImageView(); |
| 348 icon->SetImageSize(gfx::Size(message_center::kNotificationIconSize, | 356 icon->SetImageSize(gfx::Size(message_center::kNotificationIconSize, |
| 349 message_center::kNotificationIconSize)); | 357 message_center::kNotificationIconSize)); |
| 350 icon->SetImage(notification().primary_icon); | 358 icon->SetImage(notification.primary_icon()); |
| 351 icon->SetHorizontalAlignment(views::ImageView::LEADING); | 359 icon->SetHorizontalAlignment(views::ImageView::LEADING); |
| 352 icon->SetVerticalAlignment(views::ImageView::LEADING); | 360 icon->SetVerticalAlignment(views::ImageView::LEADING); |
| 353 icon->set_border(MakePadding(0, 0, 0, kIconToTextPadding)); | 361 icon->set_border(MakePadding(0, 0, 0, kIconToTextPadding)); |
| 354 layout->AddView(icon, 1, texts.size() + 1); | 362 layout->AddView(icon, 1, texts.size() + 1); |
| 355 | 363 |
| 356 // Add the text views, creating rows for them if necessary. | 364 // Add the text views, creating rows for them if necessary. |
| 357 for (size_t i = 0; i < texts.size(); ++i) { | 365 for (size_t i = 0; i < texts.size(); ++i) { |
| 358 if (i > 0) { | 366 if (i > 0) { |
| 359 layout->StartRow(0, 0); | 367 layout->StartRow(0, 0); |
| 360 layout->SkipColumns(1); | 368 layout->SkipColumns(1); |
| 361 } | 369 } |
| 362 layout->AddView(texts[i]); | 370 layout->AddView(texts[i]); |
| 363 } | 371 } |
| 364 | 372 |
| 365 // Add a text padding row if necessary. This adds some space between the last | 373 // 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 | 374 // 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. | 375 // top-justified by expanding vertically to take up any extra space. |
| 368 if (texts.size() == 0) { | 376 if (texts.size() == 0) { |
| 369 layout->SkipColumns(1); | 377 layout->SkipColumns(1); |
| 370 } else { | 378 } else { |
| 371 layout->StartRow(100, 0); | 379 layout->StartRow(100, 0); |
| 372 layout->SkipColumns(1); | 380 layout->SkipColumns(1); |
| 373 views::View* padding = new views::ImageView(); | 381 views::View* padding = new views::ImageView(); |
| 374 padding->set_border(MakePadding(kTextBottomPadding, 1, 0, 0)); | 382 padding->set_border(MakePadding(kTextBottomPadding, 1, 0, 0)); |
| 375 layout->AddView(padding); | 383 layout->AddView(padding); |
| 376 } | 384 } |
| 377 | 385 |
| 378 // Add an image row if appropriate. | 386 // Add an image row if appropriate. |
| 379 if (!notification().image.isNull()) { | 387 if (!notification.image().isNull()) { |
| 380 layout->StartRow(0, 0); | 388 layout->StartRow(0, 0); |
| 381 views::ImageView* image = new ProportionalImageView(); | 389 views::ImageView* image = new ProportionalImageView(); |
| 382 image->SetImageSize(notification().image.size()); | 390 image->SetImageSize(notification.image().size()); |
| 383 image->SetImage(notification().image); | 391 image->SetImage(notification.image()); |
| 384 image->SetHorizontalAlignment(views::ImageView::CENTER); | 392 image->SetHorizontalAlignment(views::ImageView::CENTER); |
| 385 image->SetVerticalAlignment(views::ImageView::LEADING); | 393 image->SetVerticalAlignment(views::ImageView::LEADING); |
| 386 layout->AddView(image, 2, 1); | 394 layout->AddView(image, 2, 1); |
| 387 } | 395 } |
| 388 | 396 |
| 389 // Add action button rows. | 397 // Add action button rows. |
| 390 for (size_t i = 0; i < notification().button_titles.size(); ++i) { | 398 for (size_t i = 0; i < notification.buttons().size(); ++i) { |
| 391 views::View* separator = new views::View(); | 399 views::View* separator = new views::View(); |
| 392 separator->set_background(MakeBackground(kButtonSeparatorColor)); | 400 separator->set_background(MakeBackground(kButtonSeparatorColor)); |
| 393 layout->StartRow(0, 0); | 401 layout->StartRow(0, 0); |
| 394 layout->AddView(separator, 2, 1, | 402 layout->AddView(separator, 2, 1, |
| 395 views::GridLayout::FILL, views::GridLayout::FILL, 0, 1); | 403 views::GridLayout::FILL, views::GridLayout::FILL, 0, 1); |
| 396 NotificationButton* button = new NotificationButton(this); | 404 NotificationButton* button = new NotificationButton(this); |
| 397 button->SetTitle(notification().button_titles[i]); | 405 ButtonInfo button_info = notification.buttons()[i]; |
| 398 button->SetIcon(notification().button_icons[i]); | 406 button->SetTitle(button_info.title); |
| 407 button->SetIcon(button_info.icon); |
| 399 action_buttons_.push_back(button); | 408 action_buttons_.push_back(button); |
| 400 layout->StartRow(0, 0); | 409 layout->StartRow(0, 0); |
| 401 layout->AddView(button, 2, 1, | 410 layout->AddView(button, 2, 1, |
| 402 views::GridLayout::FILL, views::GridLayout::FILL, 0, 40); | 411 views::GridLayout::FILL, views::GridLayout::FILL, 0, 40); |
| 403 } | 412 } |
| 404 | 413 |
| 405 return content_view_; | 414 return content_view_; |
| 406 } | 415 } |
| 407 | 416 |
| 408 } // namespace message_center | 417 } // namespace message_center |
| OLD | NEW |