blob: 86d12b4cad418078b66e98858025072a0e6c8925 [file] [log] [blame]
// 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/clear_server_data.h"
#include "base/command_line.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "net/url_request/url_request_context.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/insets.h"
#include "views/background.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/label.h"
#include "views/controls/separator.h"
#include "views/controls/throbber.h"
#include "views/layout/grid_layout.h"
#include "views/layout/layout_constants.h"
#include "views/widget/widget.h"
#include "views/window/dialog_client_view.h"
#include "views/window/window.h"
using views::GridLayout;
using views::ColumnSet;
// The combo box is vertically aligned to the 'time-period' label, which makes
// the combo box look a little too close to the check box above it when we use
// standard layout to separate them. We therefore add a little extra margin to
// the label, giving it a little breathing space.
static const int kExtraMarginForTimePeriodLabel = 3;
////////////////////////////////////////////////////////////////////////////////
// ClearServerDataView, public:
ClearServerDataView::ClearServerDataView(Profile* profile,
ClearDataView* clear_data_view)
: profile_(profile),
clear_data_parent_window_(clear_data_view),
allow_clear_(true) {
DCHECK(profile);
DCHECK(clear_data_view);
// Always show preferences for the original profile. Most state when off
// the record comes from the original profile, but we explicitly use
// the original profile to avoid potential problems.
profile_ = profile->GetOriginalProfile();
sync_service_ = profile_->GetProfileSyncService();
if (NULL != sync_service_) {
sync_service_->ResetClearServerDataState();
sync_service_->AddObserver(this);
}
Init();
InitControlLayout();
InitControlVisibility();
}
ClearServerDataView::~ClearServerDataView(void) {
if (NULL != sync_service_) {
sync_service_->RemoveObserver(this);
}
}
void ClearServerDataView::Init() {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
gfx::Font title_font =
rb.GetFont(ResourceBundle::BaseFont).DeriveFont(0, gfx::Font::BOLD);
flash_title_label_ = new views::Label(
UTF16ToWide(l10n_util::GetStringUTF16(IDS_CLEAR_DATA_ADOBE_FLASH_TITLE)));
flash_title_label_->SetFont(title_font);
flash_description_label_= new views::Label(UTF16ToWide(
l10n_util::GetStringUTF16(IDS_CLEAR_DATA_ADOBE_FLASH_DESCRIPTION)));
flash_link_ = new views::Link(
UTF16ToWide(l10n_util::GetStringUTF16(IDS_FLASH_STORAGE_SETTINGS)));
flash_link_->SetController(this);
chrome_sync_title_label_= new views::Label(
UTF16ToWide(l10n_util::GetStringUTF16(IDS_CLEAR_DATA_CHROME_SYNC_TITLE)));
chrome_sync_title_label_->SetFont(title_font);
chrome_sync_description_label_ = new views::Label(UTF16ToWide(
l10n_util::GetStringUTF16(IDS_CLEAR_DATA_CLEAR_SERVER_DATA_DESCRIPTION)));
clear_server_data_button_= new views::NativeButton(
this,
UTF16ToWide(l10n_util::GetStringUTF16(IDS_CLEAR_DATA_CLEAR_BUTTON)));
dashboard_label_ = new views::Label(
UTF16ToWide(l10n_util::GetStringUTF16(IDS_CLEAR_DASHBOARD_DESCRIPTION)));
dashboard_link_ = new views::Link();
dashboard_link_->SetController(this);
dashboard_link_->SetText(UTF16ToWide(
l10n_util::GetStringUTF16(IDS_SYNC_PRIVACY_DASHBOARD_LINK_LABEL)));
status_label_ = new views::Label(
UTF16ToWide(l10n_util::GetStringUTF16(IDS_CLEAR_DATA_DELETING)));
throbber_ = new views::Throbber(50, true);
}
void ClearServerDataView::InitControlLayout() {
GridLayout* layout = GridLayout::CreatePanel(this);
this->SetLayoutManager(layout);
int centered_column_set_id = 0;
ColumnSet * column_set = layout->AddColumnSet(centered_column_set_id);
column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
GridLayout::USE_PREF, 0, 0);
int left_aligned_column_set_id = 1;
column_set = layout->AddColumnSet(left_aligned_column_set_id);
column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
GridLayout::USE_PREF, 0, 0);
const int three_column_set_id = 2;
column_set = layout->AddColumnSet(three_column_set_id);
column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0,
GridLayout::USE_PREF, 0, 0);
column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
GridLayout::USE_PREF, 0, 0);
column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
GridLayout::USE_PREF, 0, 0);
AddWrappingLabelRow(layout, flash_title_label_,
centered_column_set_id, true);
AddWrappingLabelRow(layout, flash_description_label_,
centered_column_set_id, true);
layout->StartRow(0, left_aligned_column_set_id);
layout->AddView(flash_link_);
layout->AddPaddingRow(0, kPanelVertMargin);
AddWrappingLabelRow(layout, chrome_sync_title_label_,
centered_column_set_id, true);
AddWrappingLabelRow(layout, chrome_sync_description_label_,
centered_column_set_id, true);
layout->StartRow(0, three_column_set_id);
layout->AddView(clear_server_data_button_, 1, 1,
GridLayout::LEADING, GridLayout::CENTER);
layout->AddView(status_label_, 1, 1,
GridLayout::LEADING, GridLayout::CENTER);
layout->AddView(throbber_, 1, 1,
GridLayout::TRAILING, GridLayout::CENTER);
layout->AddPaddingRow(0, kPanelVertMargin);
AddWrappingLabelRow(layout, dashboard_label_, centered_column_set_id, true);
layout->StartRow(0, left_aligned_column_set_id);
layout->AddView(dashboard_link_);
}
void ClearServerDataView::InitControlVisibility() {
bool allow_clear_server_data_ui =
CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableClearServerData);
// Hide progress indicators
throbber_->SetVisible(false);
status_label_->SetVisible(false);
// Only show the sync portion if not behind the flag
chrome_sync_title_label_->SetVisible(allow_clear_server_data_ui);
chrome_sync_description_label_->SetVisible(allow_clear_server_data_ui);
clear_server_data_button_->SetVisible(allow_clear_server_data_ui);
dashboard_label_->SetVisible(allow_clear_server_data_ui);
dashboard_link_->SetVisible(allow_clear_server_data_ui);
// Enable our clear button, set false for delete_in_progress
UpdateClearButtonEnabledState(false);
}
void ClearServerDataView::SetAllowClear(bool allow) {
allow_clear_ = allow;
UpdateControlEnabledState();
}
////////////////////////////////////////////////////////////////////////////////
// ClearServerDataView, views::View implementation:
void ClearServerDataView::AddWrappingLabelRow(views::GridLayout* layout,
views::Label* label,
int id,
bool related_follows) {
label->SetMultiLine(true);
label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
layout->StartRow(0, id);
layout->AddView(label);
AddSpacing(layout, related_follows);
}
void ClearServerDataView::AddSpacing(views::GridLayout* layout,
bool related_follows) {
layout->AddPaddingRow(
0, related_follows ? views::kRelatedControlVerticalSpacing
: views::kUnrelatedControlVerticalSpacing);
}
gfx::Size ClearServerDataView::GetPreferredSize() {
// If we didn't return a preferred size, the containing view auto-sizes to
// the width of the narrowest button, which is not what we want
return gfx::Size(views::Window::GetLocalizedContentsSize(
IDS_CLEARDATA_DIALOG_WIDTH_CHARS,
IDS_CLEARDATA_DIALOG_HEIGHT_LINES));
}
////////////////////////////////////////////////////////////////////////////////
// ClearServerDataView, views::ButtonListener implementation:
void ClearServerDataView::ButtonPressed(
views::Button* sender, const views::Event& event) {
if (sender == clear_server_data_button_) {
// Protect against the unlikely case where the server received a
// message, and the syncer syncs and resets itself before the
// user tries pressing the Clear button in this dialog again.
// TODO(raz) Confirm whether we have an issue here
if (sync_service_->HasSyncSetupCompleted()) {
ConfirmMessageBoxDialog::Run(
GetWindow()->GetNativeWindow(),
this,
UTF16ToWide(l10n_util::GetStringUTF16(IDS_CONFIRM_CLEAR_DESCRIPTION)),
UTF16ToWide(l10n_util::GetStringUTF16(IDS_CONFIRM_CLEAR_TITLE)));
}
}
UpdateControlEnabledState();
}
void ClearServerDataView::LinkActivated(views::Link* source,
int event_flags) {
Browser* browser = Browser::Create(profile_);
if (source == flash_link_) {
browser->OpenURL(GURL(l10n_util::GetStringUTF8(IDS_FLASH_STORAGE_URL)),
GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
browser->window()->Show();
} else {
browser->OpenPrivacyDashboardTabAndActivate();
}
}
////////////////////////////////////////////////////////////////////////////////
// ClearServerDataView, ConfirmMessageBoxObserver implementation:
void ClearServerDataView::OnConfirmMessageAccept() {
clear_data_parent_window_->StartClearingServerData();
sync_service_->ClearServerData();
UpdateControlEnabledState();
}
void ClearServerDataView::OnConfirmMessageCancel() {
UpdateControlEnabledState();
}
////////////////////////////////////////////////////////////////////////////////
// ClearServerDataView, ProfileSyncServiceObserver implementation:
void ClearServerDataView::OnStateChanged() {
// Note that we are listening for all notifications here. Clearing from
// another browser should cause the "clear" button to go gray (if a
// notification nudges the syncer, causing OnStateChanged to be called with
// sync disabled)
UpdateControlEnabledState();
}
////////////////////////////////////////////////////////////////////////////////
// ClearServerDataView, private:
void ClearServerDataView::UpdateControlEnabledState() {
bool delete_in_progress = false;
// We only want to call Suceeded/FailedClearingServerData once, not every
// time the view is refreshed. As such, on success/failure we handle that
// state and immediately reset things back to CLEAR_NOT_STARTED.
ProfileSyncService::ClearServerDataState clear_state =
profile_->GetProfileSyncService()->GetClearServerDataState();
profile_->GetProfileSyncService()->ResetClearServerDataState();
if (NULL != sync_service_) {
sync_service_->ResetClearServerDataState();
}
switch (clear_state) {
case ProfileSyncService::CLEAR_NOT_STARTED:
// We can get here when we first start and after a failed clear (which
// does not close the tab), do nothing.
break;
case ProfileSyncService::CLEAR_CLEARING:
// Clearing buttons on all tabs are disabled at this
// point, throbber is going
status_label_->SetText(
UTF16ToWide(l10n_util::GetStringUTF16(IDS_CLEAR_DATA_SENDING)));
status_label_->SetVisible(true);
delete_in_progress = true;
break;
case ProfileSyncService::CLEAR_FAILED:
// Show an error and reallow clearing
clear_data_parent_window_->FailedClearingServerData();
status_label_->SetText(
UTF16ToWide(l10n_util::GetStringUTF16(IDS_CLEAR_DATA_ERROR)));
status_label_->SetVisible(true);
delete_in_progress = false;
break;
case ProfileSyncService::CLEAR_SUCCEEDED:
// Close the dialog box, success!
status_label_->SetVisible(false);
delete_in_progress = false;
clear_data_parent_window_->SucceededClearingServerData();
break;
}
// allow_clear can be false when a local browsing data clear is happening
// from the neighboring tab. delete_in_progress means that a clear is
// pending in the current tab.
UpdateClearButtonEnabledState(delete_in_progress);
throbber_->SetVisible(delete_in_progress);
if (delete_in_progress)
throbber_->Start();
else
throbber_->Stop();
}
void ClearServerDataView::UpdateClearButtonEnabledState(
bool delete_in_progress) {
this->clear_server_data_button_->SetEnabled(
sync_service_ != NULL &&
sync_service_->HasSyncSetupCompleted() &&
!delete_in_progress && allow_clear_);
}