summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/views/about_chrome_view.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/ui/views/about_chrome_view.cc')
-rw-r--r--chrome/browser/ui/views/about_chrome_view.cc819
1 files changed, 819 insertions, 0 deletions
diff --git a/chrome/browser/ui/views/about_chrome_view.cc b/chrome/browser/ui/views/about_chrome_view.cc
new file mode 100644
index 0000000..f16f651
--- /dev/null
+++ b/chrome/browser/ui/views/about_chrome_view.cc
@@ -0,0 +1,819 @@
+// Copyright (c) 2010 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/views/about_chrome_view.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/callback.h"
+#include "base/i18n/rtl.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "base/win/windows_version.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/views/accessible_view_helper.h"
+#include "chrome/browser/views/window.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "gfx/canvas.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/locale_settings.h"
+#include "grit/theme_resources.h"
+#include "views/controls/textfield/textfield.h"
+#include "views/controls/throbber.h"
+#include "views/standard_layout.h"
+#include "views/view_text_utils.h"
+#include "views/widget/widget.h"
+#include "views/window/window.h"
+#include "webkit/glue/webkit_glue.h"
+
+#if defined(OS_WIN)
+#include <commdlg.h>
+
+#include "base/win_util.h"
+#include "chrome/browser/views/restart_message_box.h"
+#include "chrome/installer/util/install_util.h"
+#endif
+
+namespace {
+// The pixel width of the version text field. Ideally, we'd like to have the
+// bounds set to the edge of the icon. However, the icon is not a view but a
+// part of the background, so we have to hard code the width to make sure
+// the version field doesn't overlap it.
+const int kVersionFieldWidth = 195;
+
+// These are used as placeholder text around the links in the text in the about
+// dialog.
+const wchar_t* kBeginLink = L"BEGIN_LINK";
+const wchar_t* kEndLink = L"END_LINK";
+const wchar_t* kBeginLinkChr = L"BEGIN_LINK_CHR";
+const wchar_t* kBeginLinkOss = L"BEGIN_LINK_OSS";
+const wchar_t* kEndLinkChr = L"END_LINK_CHR";
+const wchar_t* kEndLinkOss = L"END_LINK_OSS";
+
+// The background bitmap used to draw the background color for the About box
+// and the separator line (this is the image we will draw the logo on top of).
+static const SkBitmap* kBackgroundBmp = NULL;
+
+// Returns a substring from |text| between start and end.
+std::wstring StringSubRange(const std::wstring& text, size_t start,
+ size_t end) {
+ DCHECK(end > start);
+ return text.substr(start, end - start);
+}
+
+} // namespace
+
+namespace browser {
+
+ // Declared in browser_dialogs.h so that others don't
+ // need to depend on our .h.
+ views::Window* ShowAboutChromeView(gfx::NativeWindow parent,
+ Profile* profile) {
+ views::Window* about_chrome_window =
+ browser::CreateViewsWindow(parent,
+ gfx::Rect(),
+ new AboutChromeView(profile));
+ about_chrome_window->Show();
+ return about_chrome_window;
+ }
+
+} // namespace browser
+
+////////////////////////////////////////////////////////////////////////////////
+// AboutChromeView, public:
+
+AboutChromeView::AboutChromeView(Profile* profile)
+ : profile_(profile),
+ about_dlg_background_logo_(NULL),
+ about_title_label_(NULL),
+ version_label_(NULL),
+#if defined(OS_CHROMEOS)
+ os_version_label_(NULL),
+#endif
+ copyright_label_(NULL),
+ main_text_label_(NULL),
+ main_text_label_height_(0),
+ chromium_url_(NULL),
+ open_source_url_(NULL),
+ terms_of_service_url_(NULL),
+ restart_button_visible_(false),
+ chromium_url_appears_first_(true),
+ text_direction_is_rtl_(false) {
+ DCHECK(profile);
+#if defined(OS_CHROMEOS)
+ loader_.GetVersion(&consumer_,
+ NewCallback(this, &AboutChromeView::OnOSVersion), true);
+#endif
+ Init();
+
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+ google_updater_ = new GoogleUpdate();
+ google_updater_->set_status_listener(this);
+#endif
+
+ if (kBackgroundBmp == NULL) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ kBackgroundBmp = rb.GetBitmapNamed(IDR_ABOUT_BACKGROUND_COLOR);
+ }
+}
+
+AboutChromeView::~AboutChromeView() {
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+ // The Google Updater will hold a pointer to us until it reports status, so we
+ // need to let it know that we will no longer be listening.
+ if (google_updater_)
+ google_updater_->set_status_listener(NULL);
+#endif
+}
+
+void AboutChromeView::Init() {
+ text_direction_is_rtl_ = base::i18n::IsRTL();
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+
+ chrome::VersionInfo version_info;
+ if (!version_info.is_valid()) {
+ NOTREACHED() << L"Failed to initialize about window";
+ return;
+ }
+
+ current_version_ = ASCIIToWide(version_info.Version());
+
+ std::string version_modifier = platform_util::GetVersionStringModifier();
+ if (!version_modifier.empty())
+ version_details_ += L" " + ASCIIToWide(version_modifier);
+
+#if !defined(GOOGLE_CHROME_BUILD)
+ version_details_ += L" (";
+ version_details_ += ASCIIToWide(version_info.LastChange());
+ version_details_ += L")";
+#endif
+
+ // Views we will add to the *parent* of this dialog, since it will display
+ // next to the buttons which we don't draw ourselves.
+ throbber_.reset(new views::Throbber(50, true));
+ throbber_->set_parent_owned(false);
+ throbber_->SetVisible(false);
+
+ SkBitmap* success_image = rb.GetBitmapNamed(IDR_UPDATE_UPTODATE);
+ success_indicator_.SetImage(*success_image);
+ success_indicator_.set_parent_owned(false);
+
+ SkBitmap* update_available_image = rb.GetBitmapNamed(IDR_UPDATE_AVAILABLE);
+ update_available_indicator_.SetImage(*update_available_image);
+ update_available_indicator_.set_parent_owned(false);
+
+ SkBitmap* timeout_image = rb.GetBitmapNamed(IDR_UPDATE_FAIL);
+ timeout_indicator_.SetImage(*timeout_image);
+ timeout_indicator_.set_parent_owned(false);
+
+ update_label_.SetVisible(false);
+ update_label_.set_parent_owned(false);
+
+ // Regular view controls we draw by ourself. First, we add the background
+ // image for the dialog. We have two different background bitmaps, one for
+ // LTR UIs and one for RTL UIs. We load the correct bitmap based on the UI
+ // layout of the view.
+ about_dlg_background_logo_ = new views::ImageView();
+ SkBitmap* about_background_logo = rb.GetBitmapNamed(base::i18n::IsRTL() ?
+ IDR_ABOUT_BACKGROUND_RTL : IDR_ABOUT_BACKGROUND);
+
+ about_dlg_background_logo_->SetImage(*about_background_logo);
+ AddChildView(about_dlg_background_logo_);
+
+ // Add the dialog labels.
+ about_title_label_ = new views::Label(
+ l10n_util::GetString(IDS_PRODUCT_NAME));
+ about_title_label_->SetFont(ResourceBundle::GetSharedInstance().GetFont(
+ ResourceBundle::BaseFont).DeriveFont(18));
+ about_title_label_->SetColor(SK_ColorBLACK);
+ AddChildView(about_title_label_);
+
+ // This is a text field so people can copy the version number from the dialog.
+ version_label_ = new views::Textfield();
+ version_label_->SetText(WideToUTF16Hack(current_version_ + version_details_));
+ version_label_->SetReadOnly(true);
+ version_label_->RemoveBorder();
+ version_label_->SetTextColor(SK_ColorBLACK);
+ version_label_->SetBackgroundColor(SK_ColorWHITE);
+ version_label_->SetFont(ResourceBundle::GetSharedInstance().GetFont(
+ ResourceBundle::BaseFont));
+ AddChildView(version_label_);
+
+#if defined(OS_CHROMEOS)
+ os_version_label_ = new views::Textfield(views::Textfield::STYLE_MULTILINE);
+ os_version_label_->SetReadOnly(true);
+ os_version_label_->RemoveBorder();
+ os_version_label_->SetTextColor(SK_ColorBLACK);
+ os_version_label_->SetBackgroundColor(SK_ColorWHITE);
+ os_version_label_->SetFont(ResourceBundle::GetSharedInstance().GetFont(
+ ResourceBundle::BaseFont));
+ AddChildView(os_version_label_);
+#endif
+
+ // The copyright URL portion of the main label.
+ copyright_label_ = new views::Label(
+ l10n_util::GetString(IDS_ABOUT_VERSION_COPYRIGHT));
+ copyright_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ AddChildView(copyright_label_);
+
+ main_text_label_ = new views::Label(L"");
+
+ // Figure out what to write in the main label of the About box.
+ std::wstring text = l10n_util::GetString(IDS_ABOUT_VERSION_LICENSE);
+
+ chromium_url_appears_first_ =
+ text.find(kBeginLinkChr) < text.find(kBeginLinkOss);
+
+ size_t link1 = text.find(kBeginLink);
+ DCHECK(link1 != std::wstring::npos);
+ size_t link1_end = text.find(kEndLink, link1);
+ DCHECK(link1_end != std::wstring::npos);
+ size_t link2 = text.find(kBeginLink, link1_end);
+ DCHECK(link2 != std::wstring::npos);
+ size_t link2_end = text.find(kEndLink, link2);
+ DCHECK(link1_end != std::wstring::npos);
+
+ main_label_chunk1_ = text.substr(0, link1);
+ main_label_chunk2_ = StringSubRange(text, link1_end + wcslen(kEndLinkOss),
+ link2);
+ main_label_chunk3_ = text.substr(link2_end + wcslen(kEndLinkOss));
+
+ // The Chromium link within the main text of the dialog.
+ chromium_url_ = new views::Link(
+ StringSubRange(text, text.find(kBeginLinkChr) + wcslen(kBeginLinkChr),
+ text.find(kEndLinkChr)));
+ AddChildView(chromium_url_);
+ chromium_url_->SetController(this);
+
+ // The Open Source link within the main text of the dialog.
+ open_source_url_ = new views::Link(
+ StringSubRange(text, text.find(kBeginLinkOss) + wcslen(kBeginLinkOss),
+ text.find(kEndLinkOss)));
+ AddChildView(open_source_url_);
+ open_source_url_->SetController(this);
+
+ // Add together all the strings in the dialog for the purpose of calculating
+ // the height of the dialog. The space for the Terms of Service string is not
+ // included (it is added later, if needed).
+ std::wstring full_text = main_label_chunk1_ + chromium_url_->GetText() +
+ main_label_chunk2_ + open_source_url_->GetText() +
+ main_label_chunk3_;
+
+ dialog_dimensions_ = views::Window::GetLocalizedContentsSize(
+ IDS_ABOUT_DIALOG_WIDTH_CHARS,
+ IDS_ABOUT_DIALOG_MINIMUM_HEIGHT_LINES);
+
+ // Create a label and add the full text so we can query it for the height.
+ views::Label dummy_text(full_text);
+ dummy_text.SetMultiLine(true);
+ gfx::Font font =
+ ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
+
+ // Add up the height of the various elements on the page.
+ int height = about_background_logo->height() +
+ kRelatedControlVerticalSpacing +
+ // Copyright line.
+ font.GetHeight() +
+ // Main label.
+ dummy_text.GetHeightForWidth(
+ dialog_dimensions_.width() - (2 * kPanelHorizMargin)) +
+ kRelatedControlVerticalSpacing;
+
+#if defined(GOOGLE_CHROME_BUILD)
+ std::vector<size_t> url_offsets;
+ text = l10n_util::GetStringF(IDS_ABOUT_TERMS_OF_SERVICE,
+ std::wstring(),
+ std::wstring(),
+ &url_offsets);
+
+ main_label_chunk4_ = text.substr(0, url_offsets[0]);
+ main_label_chunk5_ = text.substr(url_offsets[0]);
+
+ // The Terms of Service URL at the bottom.
+ terms_of_service_url_ =
+ new views::Link(l10n_util::GetString(IDS_TERMS_OF_SERVICE));
+ AddChildView(terms_of_service_url_);
+ terms_of_service_url_->SetController(this);
+
+ // Add the Terms of Service line and some whitespace.
+ height += font.GetHeight() + kRelatedControlVerticalSpacing;
+#endif
+
+ // Use whichever is greater (the calculated height or the specified minimum
+ // height).
+ dialog_dimensions_.set_height(std::max(height, dialog_dimensions_.height()));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// AboutChromeView, views::View implementation:
+
+gfx::Size AboutChromeView::GetPreferredSize() {
+ return dialog_dimensions_;
+}
+
+void AboutChromeView::Layout() {
+ gfx::Size panel_size = GetPreferredSize();
+
+ // Background image for the dialog.
+ gfx::Size sz = about_dlg_background_logo_->GetPreferredSize();
+ // Used to position main text below.
+ int background_image_height = sz.height();
+ about_dlg_background_logo_->SetBounds(panel_size.width() - sz.width(), 0,
+ sz.width(), sz.height());
+
+ // First label goes to the top left corner.
+ sz = about_title_label_->GetPreferredSize();
+ about_title_label_->SetBounds(kPanelHorizMargin, kPanelVertMargin,
+ sz.width(), sz.height());
+
+ // Then we have the version number right below it.
+ sz = version_label_->GetPreferredSize();
+ version_label_->SetBounds(kPanelHorizMargin,
+ about_title_label_->y() +
+ about_title_label_->height() +
+ kRelatedControlVerticalSpacing,
+ kVersionFieldWidth,
+ sz.height());
+
+#if defined(OS_CHROMEOS)
+ // Then we have the version number right below it.
+ sz = os_version_label_->GetPreferredSize();
+ os_version_label_->SetBounds(
+ kPanelHorizMargin,
+ version_label_->y() +
+ version_label_->height() +
+ kRelatedControlVerticalSpacing,
+ kVersionFieldWidth,
+ sz.height());
+#endif
+
+ // For the width of the main text label we want to use up the whole panel
+ // width and remaining height, minus a little margin on each side.
+ int y_pos = background_image_height + kRelatedControlVerticalSpacing;
+ sz.set_width(panel_size.width() - 2 * kPanelHorizMargin);
+
+ // Draw the text right below the background image.
+ copyright_label_->SetBounds(kPanelHorizMargin,
+ y_pos,
+ sz.width(),
+ sz.height());
+
+ // Then the main_text_label.
+ main_text_label_->SetBounds(kPanelHorizMargin,
+ copyright_label_->y() +
+ copyright_label_->height(),
+ sz.width(),
+ main_text_label_height_);
+
+ // Get the y-coordinate of our parent so we can position the text left of the
+ // buttons at the bottom.
+ gfx::Rect parent_bounds = GetParent()->GetLocalBounds(false);
+
+ sz = throbber_->GetPreferredSize();
+ int throbber_topleft_x = kPanelHorizMargin;
+ int throbber_topleft_y = parent_bounds.bottom() - sz.height() -
+ kButtonVEdgeMargin - 3;
+ throbber_->SetBounds(throbber_topleft_x, throbber_topleft_y,
+ sz.width(), sz.height());
+
+ // This image is hidden (see ViewHierarchyChanged) and displayed on demand.
+ sz = success_indicator_.GetPreferredSize();
+ success_indicator_.SetBounds(throbber_topleft_x, throbber_topleft_y,
+ sz.width(), sz.height());
+
+ // This image is hidden (see ViewHierarchyChanged) and displayed on demand.
+ sz = update_available_indicator_.GetPreferredSize();
+ update_available_indicator_.SetBounds(throbber_topleft_x, throbber_topleft_y,
+ sz.width(), sz.height());
+
+ // This image is hidden (see ViewHierarchyChanged) and displayed on demand.
+ sz = timeout_indicator_.GetPreferredSize();
+ timeout_indicator_.SetBounds(throbber_topleft_x, throbber_topleft_y,
+ sz.width(), sz.height());
+
+ // The update label should be at the bottom of the screen, to the right of
+ // the throbber. We specify width to the end of the dialog because it contains
+ // variable length messages.
+ sz = update_label_.GetPreferredSize();
+ int update_label_x = throbber_->x() + throbber_->width() +
+ kRelatedControlHorizontalSpacing;
+ update_label_.SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ update_label_.SetBounds(update_label_x,
+ throbber_topleft_y + 1,
+ parent_bounds.width() - update_label_x,
+ sz.height());
+
+ if (!accessible_view_helper_.get())
+ accessible_view_helper_.reset(
+ new AccessibleViewHelper(GetParent(), profile_));
+}
+
+
+void AboutChromeView::Paint(gfx::Canvas* canvas) {
+ views::View::Paint(canvas);
+
+ // Draw the background image color (and the separator) across the dialog.
+ // This will become the background for the logo image at the top of the
+ // dialog.
+ canvas->TileImageInt(*kBackgroundBmp, 0, 0,
+ dialog_dimensions_.width(), kBackgroundBmp->height());
+
+ gfx::Font font =
+ ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
+
+ const gfx::Rect label_bounds = main_text_label_->bounds();
+
+ views::Link* link1 =
+ chromium_url_appears_first_ ? chromium_url_ : open_source_url_;
+ views::Link* link2 =
+ chromium_url_appears_first_ ? open_source_url_ : chromium_url_;
+ gfx::Rect* rect1 = chromium_url_appears_first_ ?
+ &chromium_url_rect_ : &open_source_url_rect_;
+ gfx::Rect* rect2 = chromium_url_appears_first_ ?
+ &open_source_url_rect_ : &chromium_url_rect_;
+
+ // This struct keeps track of where to write the next word (which x,y
+ // pixel coordinate). This struct is updated after drawing text and checking
+ // if we need to wrap.
+ gfx::Size position;
+ // Draw the first text chunk and position the Chromium url.
+ view_text_utils::DrawTextAndPositionUrl(canvas, main_text_label_,
+ main_label_chunk1_, link1, rect1, &position, text_direction_is_rtl_,
+ label_bounds, font);
+ // Draw the second text chunk and position the Open Source url.
+ view_text_utils::DrawTextAndPositionUrl(canvas, main_text_label_,
+ main_label_chunk2_, link2, rect2, &position, text_direction_is_rtl_,
+ label_bounds, font);
+ // Draw the third text chunk (which has no URL associated with it).
+ view_text_utils::DrawTextAndPositionUrl(canvas, main_text_label_,
+ main_label_chunk3_, NULL, NULL, &position, text_direction_is_rtl_,
+ label_bounds, font);
+
+#if defined(GOOGLE_CHROME_BUILD)
+ // Insert a line break and some whitespace.
+ position.set_width(0);
+ position.Enlarge(0, font.GetHeight() + kRelatedControlVerticalSpacing);
+
+ // And now the Terms of Service and position the TOS url.
+ view_text_utils::DrawTextAndPositionUrl(canvas, main_text_label_,
+ main_label_chunk4_, terms_of_service_url_, &terms_of_service_url_rect_,
+ &position, text_direction_is_rtl_, label_bounds, font);
+ // The last text chunk doesn't have a URL associated with it.
+ view_text_utils::DrawTextAndPositionUrl(canvas, main_text_label_,
+ main_label_chunk5_, NULL, NULL, &position, text_direction_is_rtl_,
+ label_bounds, font);
+
+ // Position the TOS URL within the main label.
+ terms_of_service_url_->SetBounds(terms_of_service_url_rect_.x(),
+ terms_of_service_url_rect_.y(),
+ terms_of_service_url_rect_.width(),
+ terms_of_service_url_rect_.height());
+#endif
+
+ // Position the URLs within the main label. First position the Chromium URL
+ // within the main label.
+ chromium_url_->SetBounds(chromium_url_rect_.x(),
+ chromium_url_rect_.y(),
+ chromium_url_rect_.width(),
+ chromium_url_rect_.height());
+ // Then position the Open Source URL within the main label.
+ open_source_url_->SetBounds(open_source_url_rect_.x(),
+ open_source_url_rect_.y(),
+ open_source_url_rect_.width(),
+ open_source_url_rect_.height());
+
+ // Save the height so we can set the bounds correctly.
+ main_text_label_height_ = position.height() + font.GetHeight();
+}
+
+void AboutChromeView::ViewHierarchyChanged(bool is_add,
+ views::View* parent,
+ views::View* child) {
+ // Since we want some of the controls to show up in the same visual row
+ // as the buttons, which are provided by the framework, we must add the
+ // buttons to the non-client view, which is the parent of this view.
+ // Similarly, when we're removed from the view hierarchy, we must take care
+ // to remove these items as well.
+ if (child == this) {
+ if (is_add) {
+ parent->AddChildView(&update_label_);
+ parent->AddChildView(throbber_.get());
+ parent->AddChildView(&success_indicator_);
+ success_indicator_.SetVisible(false);
+ parent->AddChildView(&update_available_indicator_);
+ update_available_indicator_.SetVisible(false);
+ parent->AddChildView(&timeout_indicator_);
+ timeout_indicator_.SetVisible(false);
+
+#if defined(OS_WIN)
+ // On-demand updates for Chrome don't work in Vista RTM when UAC is turned
+ // off. So, in this case we just want the About box to not mention
+ // on-demand updates. Silent updates (in the background) should still
+ // work as before - enabling UAC or installing the latest service pack
+ // for Vista is another option.
+ int service_pack_major = 0, service_pack_minor = 0;
+ base::win::GetServicePackLevel(&service_pack_major, &service_pack_minor);
+ if (win_util::UserAccountControlIsEnabled() ||
+ base::win::GetVersion() == base::win::VERSION_XP ||
+ (base::win::GetVersion() == base::win::VERSION_VISTA &&
+ service_pack_major >= 1) ||
+ base::win::GetVersion() > base::win::VERSION_VISTA) {
+ UpdateStatus(UPGRADE_CHECK_STARTED, GOOGLE_UPDATE_NO_ERROR);
+ // CheckForUpdate(false, ...) means don't upgrade yet.
+ google_updater_->CheckForUpdate(false, window());
+ }
+#elif defined(OS_CHROMEOS)
+ UpdateStatus(UPGRADE_CHECK_STARTED, GOOGLE_UPDATE_NO_ERROR);
+ // CheckForUpdate(false, ...) means don't upgrade yet.
+ google_updater_->CheckForUpdate(false, window());
+#endif
+ } else {
+ parent->RemoveChildView(&update_label_);
+ parent->RemoveChildView(throbber_.get());
+ parent->RemoveChildView(&success_indicator_);
+ parent->RemoveChildView(&update_available_indicator_);
+ parent->RemoveChildView(&timeout_indicator_);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// AboutChromeView, views::DialogDelegate implementation:
+
+std::wstring AboutChromeView::GetDialogButtonLabel(
+ MessageBoxFlags::DialogButton button) const {
+ if (button == MessageBoxFlags::DIALOGBUTTON_OK) {
+ return l10n_util::GetString(IDS_RESTART_AND_UPDATE);
+ } else if (button == MessageBoxFlags::DIALOGBUTTON_CANCEL) {
+ if (restart_button_visible_)
+ return l10n_util::GetString(IDS_NOT_NOW);
+ // The OK button (which is the default button) has been re-purposed to be
+ // 'Restart Now' so we want the Cancel button should have the label
+ // OK but act like a Cancel button in all other ways.
+ return l10n_util::GetString(IDS_OK);
+ }
+
+ NOTREACHED();
+ return L"";
+}
+
+std::wstring AboutChromeView::GetWindowTitle() const {
+ return l10n_util::GetString(IDS_ABOUT_CHROME_TITLE);
+}
+
+bool AboutChromeView::IsDialogButtonEnabled(
+ MessageBoxFlags::DialogButton button) const {
+ if (button == MessageBoxFlags::DIALOGBUTTON_OK && !restart_button_visible_)
+ return false;
+
+ return true;
+}
+
+bool AboutChromeView::IsDialogButtonVisible(
+ MessageBoxFlags::DialogButton button) const {
+ if (button == MessageBoxFlags::DIALOGBUTTON_OK && !restart_button_visible_)
+ return false;
+
+ return true;
+}
+
+// (on ChromeOS) the default focus is ending up in the version field when
+// the update button is hidden. This forces the focus to always be on the
+// OK button (which is the dialog cancel button, see GetDialogButtonLabel
+// above).
+int AboutChromeView::GetDefaultDialogButton() const {
+ return MessageBoxFlags::DIALOGBUTTON_CANCEL;
+}
+
+bool AboutChromeView::CanResize() const {
+ return false;
+}
+
+bool AboutChromeView::CanMaximize() const {
+ return false;
+}
+
+bool AboutChromeView::IsAlwaysOnTop() const {
+ return false;
+}
+
+bool AboutChromeView::HasAlwaysOnTopMenu() const {
+ return false;
+}
+
+bool AboutChromeView::IsModal() const {
+ return true;
+}
+
+bool AboutChromeView::Accept() {
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+ // Set the flag to restore the last session on shutdown.
+ PrefService* pref_service = g_browser_process->local_state();
+ pref_service->SetBoolean(prefs::kRestartLastSessionOnShutdown, true);
+ BrowserList::CloseAllBrowsersAndExit();
+#endif
+
+ return true;
+}
+
+views::View* AboutChromeView::GetContentsView() {
+ return this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// AboutChromeView, views::LinkController implementation:
+
+void AboutChromeView::LinkActivated(views::Link* source,
+ int event_flags) {
+ GURL url;
+ if (source == terms_of_service_url_)
+ url = GURL(chrome::kAboutTermsURL);
+ else if (source == chromium_url_)
+ url = GURL(l10n_util::GetStringUTF16(IDS_CHROMIUM_PROJECT_URL));
+ else if (source == open_source_url_)
+ url = GURL(chrome::kAboutCreditsURL);
+ else
+ NOTREACHED() << "Unknown link source";
+
+ Browser* browser = BrowserList::GetLastActive();
+#if defined(OS_CHROMEOS)
+ browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
+#else
+ browser->OpenURL(url, GURL(), NEW_WINDOW, PageTransition::LINK);
+#endif
+}
+
+#if defined(OS_CHROMEOS)
+void AboutChromeView::OnOSVersion(
+ chromeos::VersionLoader::Handle handle,
+ std::string version) {
+
+ // This is a hack to "wrap" the very long Test Build version after
+ // the version number, the remaining text won't be visible but can
+ // be selected, copied, pasted.
+ std::string::size_type pos = version.find(" (Test Build");
+ if (pos != std::string::npos)
+ version.replace(pos, 1, "\n");
+
+ os_version_label_->SetText(UTF8ToUTF16(version));
+}
+#endif
+
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+////////////////////////////////////////////////////////////////////////////////
+// AboutChromeView, GoogleUpdateStatusListener implementation:
+
+void AboutChromeView::OnReportResults(GoogleUpdateUpgradeResult result,
+ GoogleUpdateErrorCode error_code,
+ const std::wstring& version) {
+ // Drop the last reference to the object so that it gets cleaned up here.
+ google_updater_ = NULL;
+
+ // Make a note of which version Google Update is reporting is the latest
+ // version.
+ new_version_available_ = version;
+ UpdateStatus(result, error_code);
+}
+////////////////////////////////////////////////////////////////////////////////
+// AboutChromeView, private:
+
+void AboutChromeView::UpdateStatus(GoogleUpdateUpgradeResult result,
+ GoogleUpdateErrorCode error_code) {
+#if !defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS)
+ // For Chromium builds it would show an error message.
+ // But it looks weird because in fact there is no error,
+ // just the update server is not available for non-official builds.
+ return;
+#endif
+ bool show_success_indicator = false;
+ bool show_update_available_indicator = false;
+ bool show_timeout_indicator = false;
+ bool show_throbber = false;
+ bool show_update_label = true; // Always visible, except at start.
+
+ switch (result) {
+ case UPGRADE_STARTED:
+ UserMetrics::RecordAction(UserMetricsAction("Upgrade_Started"), profile_);
+ show_throbber = true;
+ update_label_.SetText(l10n_util::GetString(IDS_UPGRADE_STARTED));
+ break;
+ case UPGRADE_CHECK_STARTED:
+ UserMetrics::RecordAction(UserMetricsAction("UpgradeCheck_Started"),
+ profile_);
+ show_throbber = true;
+ update_label_.SetText(l10n_util::GetString(IDS_UPGRADE_CHECK_STARTED));
+ break;
+ case UPGRADE_IS_AVAILABLE:
+ UserMetrics::RecordAction(
+ UserMetricsAction("UpgradeCheck_UpgradeIsAvailable"), profile_);
+ DCHECK(!google_updater_); // Should have been nulled out already.
+ google_updater_ = new GoogleUpdate();
+ google_updater_->set_status_listener(this);
+ UpdateStatus(UPGRADE_STARTED, GOOGLE_UPDATE_NO_ERROR);
+ // CheckForUpdate(true,...) means perform upgrade if new version found.
+ google_updater_->CheckForUpdate(true, window());
+ // TODO(seanparent): Need to see if this code needs to change to
+ // force a machine restart.
+ return;
+ case UPGRADE_ALREADY_UP_TO_DATE: {
+ // The extra version check is necessary on Windows because the application
+ // may be already up to date on disk though the running app is still
+ // out of date. Chrome OS doesn't quite have this issue since the
+ // OS/App are updated together. If a newer version of the OS has been
+ // staged then UPGRADE_SUCESSFUL will be returned.
+#if defined(OS_WIN)
+ // Google Update reported that Chrome is up-to-date. Now make sure that we
+ // are running the latest version and if not, notify the user by falling
+ // into the next case of UPGRADE_SUCCESSFUL.
+ scoped_ptr<installer::Version> installed_version(
+ InstallUtil::GetChromeVersion(false));
+ scoped_ptr<installer::Version> running_version(
+ installer::Version::GetVersionFromString(current_version_));
+ if (!installed_version.get() ||
+ !installed_version->IsHigherThan(running_version.get())) {
+#endif
+ UserMetrics::RecordAction(
+ UserMetricsAction("UpgradeCheck_AlreadyUpToDate"), profile_);
+#if defined(OS_CHROMEOS)
+ std::wstring update_label_text =
+ l10n_util::GetStringF(IDS_UPGRADE_ALREADY_UP_TO_DATE,
+ l10n_util::GetString(IDS_PRODUCT_NAME));
+#else
+ std::wstring update_label_text =
+ l10n_util::GetStringF(IDS_UPGRADE_ALREADY_UP_TO_DATE,
+ l10n_util::GetString(IDS_PRODUCT_NAME),
+ current_version_);
+#endif
+ if (base::i18n::IsRTL()) {
+ update_label_text.push_back(
+ static_cast<wchar_t>(base::i18n::kLeftToRightMark));
+ }
+ update_label_.SetText(update_label_text);
+ show_success_indicator = true;
+ break;
+#if defined(OS_WIN)
+ }
+#endif
+ // No break here as we want to notify user about upgrade if there is one.
+ }
+ case UPGRADE_SUCCESSFUL: {
+ if (result == UPGRADE_ALREADY_UP_TO_DATE)
+ UserMetrics::RecordAction(
+ UserMetricsAction("UpgradeCheck_AlreadyUpgraded"), profile_);
+ else
+ UserMetrics::RecordAction(UserMetricsAction("UpgradeCheck_Upgraded"),
+ profile_);
+ restart_button_visible_ = true;
+ const std::wstring& update_string =
+ l10n_util::GetStringF(IDS_UPGRADE_SUCCESSFUL_RESTART,
+ l10n_util::GetString(IDS_PRODUCT_NAME));
+ update_label_.SetText(update_string);
+ show_success_indicator = true;
+ break;
+ }
+ case UPGRADE_ERROR:
+ UserMetrics::RecordAction(UserMetricsAction("UpgradeCheck_Error"),
+ profile_);
+ restart_button_visible_ = false;
+ update_label_.SetText(l10n_util::GetStringF(IDS_UPGRADE_ERROR,
+ UTF8ToWide(base::IntToString(error_code))));
+ show_timeout_indicator = true;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ success_indicator_.SetVisible(show_success_indicator);
+ update_available_indicator_.SetVisible(show_update_available_indicator);
+ timeout_indicator_.SetVisible(show_timeout_indicator);
+ update_label_.SetVisible(show_update_label);
+ throbber_->SetVisible(show_throbber);
+ if (show_throbber)
+ throbber_->Start();
+ else
+ throbber_->Stop();
+
+ // We have updated controls on the parent, so we need to update its layout.
+ View* parent = GetParent();
+ parent->Layout();
+
+ // Check button may have appeared/disappeared. We cannot call this during
+ // ViewHierarchyChanged because the |window()| pointer hasn't been set yet.
+ if (window())
+ GetDialogClientView()->UpdateDialogButtons();
+}
+
+#endif