Chromium Code Reviews| Index: chrome/browser/ui/views/critical_notification_bubble_view.cc |
| =================================================================== |
| --- chrome/browser/ui/views/critical_notification_bubble_view.cc (revision 0) |
| +++ chrome/browser/ui/views/critical_notification_bubble_view.cc (revision 0) |
| @@ -0,0 +1,198 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/ui/views/critical_notification_bubble_view.h" |
| + |
| +#include "base/string_number_conversions.h" |
| +#include "base/utf_string_conversions.h" |
| +#include "chrome/browser/ui/browser_list.h" |
| +#include "chrome/browser/upgrade_detector.h" |
| +#include "content/browser/user_metrics.h" |
| +#include "grit/chromium_strings.h" |
| +#include "grit/generated_resources.h" |
| +#include "grit/locale_settings.h" |
| +#include "grit/theme_resources.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| +#include "ui/base/resource/resource_bundle.h" |
| +#include "views/controls/button/text_button.h" |
| +#include "views/controls/image_view.h" |
| +#include "views/controls/label.h" |
| + |
| +namespace { |
| + |
| +// Layout constants. |
| +const int kPaddingAfterImage = 5; |
| +const int kPaddingAboveButtonRow = 4; |
| +const int kPaddingBetweenButtons = 7; |
| + |
| +// How long to give the user until auto-restart if no action is taken. The code |
| +// assumes this to be less than a minute. |
| +const int kCountdownDuration = 30; // Seconds. |
| + |
| +// How often to refresh the bubble UI to update the counter. As long as the |
| +// countdown is in seconds, this should be 1000 or lower. |
| +const int kRefreshBubbleEvery = 1000; // Millisecond. |
| + |
| +} // namespace |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// CriticalNotificationBubbleView |
| + |
| +Bubble* CriticalNotificationBubbleView::bubble_ = NULL; |
| + |
| +CriticalNotificationBubbleView::CriticalNotificationBubbleView() { |
| + bubble_created_ = base::Time::Now(); |
| + |
| + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| + |
| + image_ = new views::ImageView(); |
| + image_->SetImage(ResourceBundle::GetSharedInstance(). |
| + GetBitmapNamed(IDR_UPDATE_MENU3)); |
| + AddChildView(image_); |
| + |
| + headline_ = new views::Label(); |
| + headline_->SetFont(rb.GetFont(ResourceBundle::MediumFont)); |
| + UpdateBubbleHeadline(GetRemainingTime()); |
| + AddChildView(headline_); |
| + |
| + message_ = new views::Label(); |
| + message_->SetMultiLine(true); |
| + message_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
| + message_->SetText(UTF16ToWide( |
| + l10n_util::GetStringFUTF16(IDS_CRITICAL_NOTIFICATION_TEXT, |
| + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)))); |
| + AddChildView(message_); |
| + |
| + restart_button_ = new views::NativeTextButton(this, |
| + UTF16ToWide(l10n_util::GetStringUTF16( |
| + IDS_CRITICAL_NOTIFICATION_RESTART))); |
| + restart_button_->SetIsDefault(true); |
| + AddChildView(restart_button_); |
| + dismiss_button_ = new views::NativeTextButton(this, UTF16ToWide( |
| + l10n_util::GetStringUTF16(IDS_CRITICAL_NOTIFICATION_DISMISS))); |
| + AddChildView(dismiss_button_); |
| + |
| + if (bubble_) |
| + bubble_->Close(); |
| + |
| + refresh_timer_.Start(FROM_HERE, |
| + base::TimeDelta::FromMilliseconds(kRefreshBubbleEvery), |
| + this, &CriticalNotificationBubbleView::OnCountdown); |
| + |
| + UserMetrics::RecordAction(UserMetricsAction("CriticalNotificationShown")); |
| +} |
| + |
| +CriticalNotificationBubbleView::~CriticalNotificationBubbleView() { |
| +} |
| + |
| +int CriticalNotificationBubbleView::GetRemainingTime() { |
| + base::TimeDelta time_lapsed = base::Time::Now() - bubble_created_; |
| + return kCountdownDuration - time_lapsed.InSeconds(); |
| +} |
| + |
| +void CriticalNotificationBubbleView::UpdateBubbleHeadline(int seconds) { |
| + headline_->SetText(UTF16ToWide( |
| + l10n_util::GetStringFUTF16(IDS_CRITICAL_NOTIFICATION_HEADLINE, |
| + l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), |
| + base::IntToString16(seconds)))); |
| +} |
| + |
| +void CriticalNotificationBubbleView::OnCountdown() { |
| + int seconds = GetRemainingTime(); |
| + if (seconds <= 0) { |
| + // Time's up! |
| + UserMetrics::RecordAction( |
| + UserMetricsAction("CriticalNotification_AutoRestart")); |
| + refresh_timer_.Stop(); |
| + BrowserList::AttemptRestart(); |
|
Ben Goodger (Google)
2011/10/12 15:10:45
btw, what happens if a tab stops shutdown (with an
Finnur
2011/10/13 14:34:10
What happens? Good question. The "Leave-this-page?
|
| + } else { |
| + // Update the counter. |
| + UpdateBubbleHeadline(seconds); |
| + bubble_->ScheduleDraw(); |
| + } |
| +} |
| + |
| +gfx::Size CriticalNotificationBubbleView::GetPreferredSize() { |
| + int width = views::Widget::GetLocalizedContentsWidth( |
| + IDS_CRUCIAL_NOTIFICATION_BUBBLE_WIDTH_CHARS); |
| + gfx::Size size(width, 0); |
| + |
| + gfx::Size headline = headline_->GetPreferredSize(); |
| + int height = message_->GetHeightForWidth(size.width()); |
| + gfx::Size button_row = dismiss_button_->GetPreferredSize(); |
| + |
| + size.set_height(headline.height() + |
| + height + |
| + kPaddingAboveButtonRow + |
| + button_row.height()); |
| + return size; |
| +} |
| + |
| +void CriticalNotificationBubbleView::Layout() { |
| + gfx::Size bubble_size = GetPreferredSize(); |
| + |
| + gfx::Size sz = image_->GetPreferredSize(); |
| + image_->SetBounds(0, 0, sz.width(), sz.height()); |
| + |
| + sz = headline_->GetPreferredSize(); |
| + headline_->SetBounds(image_->width() + kPaddingAfterImage, |
| + (image_->height() - sz.height()) / 2, |
| + sz.width(), sz.height()); |
| + |
| + sz = message_->GetPreferredSize(); |
| + int height = message_->GetHeightForWidth(bubble_size.width()); |
| + message_->SetBounds(0, headline_->height(), bubble_size.width(), height); |
| + |
| + sz = dismiss_button_->GetPreferredSize(); |
| + dismiss_button_->SetBounds(bubble_size.width() - sz.width(), |
| + message_->y() + message_->height() + |
| + kPaddingAboveButtonRow, |
| + sz.width(), |
| + sz.height()); |
| + |
| + sz = restart_button_->GetPreferredSize(); |
| + restart_button_->SetBounds(dismiss_button_->x() - sz.width() - |
| + kPaddingBetweenButtons, |
| + dismiss_button_->y(), |
| + sz.width(), |
| + sz.height()); |
| +} |
| + |
| +void CriticalNotificationBubbleView::ButtonPressed( |
| + views::Button* sender, const views::Event& event) { |
| + UpgradeDetector::GetInstance()->acknowledge_critical_update(); |
| + |
| + if (sender == restart_button_) { |
| + UserMetrics::RecordAction( |
| + UserMetricsAction("CriticalNotification_Restart")); |
| + BrowserList::AttemptRestart(); |
| + } else if (sender == dismiss_button_) { |
| + UserMetrics::RecordAction(UserMetricsAction("CriticalNotification_Ignore")); |
| + bubble_->Close(); |
| + } else { |
| + NOTREACHED(); |
| + } |
| +} |
| + |
| +void CriticalNotificationBubbleView::BubbleClosing(Bubble* bubble, |
| + bool closed_by_escape) { |
| + bubble_ = NULL; |
| + |
| + refresh_timer_.Stop(); |
| + |
| + if (closed_by_escape) |
| + UpgradeDetector::GetInstance()->acknowledge_critical_update(); |
| +} |
| + |
| +bool CriticalNotificationBubbleView::CloseOnEscape() { |
|
Ben Goodger (Google)
2011/10/12 15:10:45
general bubble design notes for future reference:
|
| + return true; |
| +} |
| + |
| +bool CriticalNotificationBubbleView::FadeInOnShow() { |
| + return true; |
| +} |
| + |
| +string16 CriticalNotificationBubbleView::accessible_name() { |
| + return ASCIIToWide("CriticalNotification"); |
| +} |
| Property changes on: chrome\browser\ui\views\critical_notification_bubble_view.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |