summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authortim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-15 21:52:28 +0000
committertim@chromium.org <tim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-15 21:52:28 +0000
commitd742d2f41fd7035ef040a1b76bd5bcd93ae9b0ac (patch)
tree1593105e3c5b59d87bcedbb465eb9d67500f3fdd /chrome/browser
parent53556e1b386f14de94d97351e47774b97c0ed753 (diff)
downloadchromium_src-d742d2f41fd7035ef040a1b76bd5bcd93ae9b0ac.zip
chromium_src-d742d2f41fd7035ef040a1b76bd5bcd93ae9b0ac.tar.gz
chromium_src-d742d2f41fd7035ef040a1b76bd5bcd93ae9b0ac.tar.bz2
Facelifts to sync UI
BUG=23136,24858,21596 TEST=SyncSetupWizardTest Review URL: http://codereview.chromium.org/270081 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29197 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/browser_resources.grd1
-rw-r--r--chrome/browser/dom_ui/new_tab_page_sync_handler.cc56
-rw-r--r--chrome/browser/dom_ui/new_tab_page_sync_handler.h11
-rw-r--r--chrome/browser/resources/new_new_tab.js1
-rw-r--r--chrome/browser/sync/profile_sync_service.cc24
-rw-r--r--chrome/browser/sync/resources/gaia_login.html13
-rw-r--r--chrome/browser/sync/resources/merge_and_sync.html57
-rw-r--r--chrome/browser/sync/resources/setup_done.html59
-rw-r--r--chrome/browser/sync/resources/setup_flow.html7
-rw-r--r--chrome/browser/views/confirm_message_box_dialog.cc37
-rw-r--r--chrome/browser/views/confirm_message_box_dialog.h35
-rw-r--r--chrome/browser/views/options/content_page_view.cc19
-rw-r--r--chrome/browser/views/options/content_page_view.h7
-rw-r--r--chrome/browser/views/sync/sync_setup_flow.cc33
-rw-r--r--chrome/browser/views/sync/sync_setup_flow.h3
-rw-r--r--chrome/browser/views/sync/sync_setup_wizard.cc31
-rw-r--r--chrome/browser/views/sync/sync_setup_wizard.h16
-rw-r--r--chrome/browser/views/sync/sync_setup_wizard_unittest.cc22
-rw-r--r--chrome/browser/views/toolbar_view.cc17
19 files changed, 352 insertions, 97 deletions
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 98d558a..05e6342 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -48,6 +48,7 @@ without changes to the corresponding grd file. ek -->
<include name="IDR_GAIA_LOGIN_HTML" file="sync\resources\gaia_login.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_SYNC_SETUP_FLOW_HTML" file="sync\resources\setup_flow.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_MERGE_AND_SYNC_HTML" file="sync\resources\merge_and_sync.html" flattenhtml="true" type="BINDATA" />
+ <include name="IDR_SYNC_SETUP_DONE_HTML" file="sync\resources\setup_done.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_BLACKLIST_HTML" file="resources\privacy_blacklist_block.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_BLACKLIST_IMAGE" file="resources\privacy_blacklist_block.png" type="BINDATA" />
<include name="IDR_DEFAULT_EXTENSION_ICON_128" file="resources\default_extension_icon_128.png" type="BINDATA" />
diff --git a/chrome/browser/dom_ui/new_tab_page_sync_handler.cc b/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
index 0b26492..e5239a5 100644
--- a/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
+++ b/chrome/browser/dom_ui/new_tab_page_sync_handler.cc
@@ -80,6 +80,20 @@ NewTabPageSyncHandler::~NewTabPageSyncHandler() {
sync_service_->RemoveObserver(this);
}
+// static
+NewTabPageSyncHandler::MessageType
+ NewTabPageSyncHandler::FromSyncStatusMessageType(
+ SyncStatusUIHelper::MessageType type) {
+ switch (type) {
+ case SyncStatusUIHelper::SYNC_ERROR:
+ return SYNC_ERROR;
+ case SyncStatusUIHelper::PRE_SYNCED:
+ case SyncStatusUIHelper::SYNCED:
+ default:
+ return HIDE;
+ }
+}
+
DOMMessageHandler* NewTabPageSyncHandler::Attach(DOMUI* dom_ui) {
sync_service_ = dom_ui->GetProfile()->GetProfileSyncService();
DCHECK(sync_service_); // This shouldn't get called by an incognito NTP.
@@ -100,8 +114,7 @@ void NewTabPageSyncHandler::HandleGetSyncMessage(const Value* value) {
}
void NewTabPageSyncHandler::HideSyncStatusSection() {
- SendSyncMessageToPage(SyncStatusUIHelper::PRE_SYNCED, std::string(),
- std::string());
+ SendSyncMessageToPage(HIDE, std::string(), std::string());
}
void NewTabPageSyncHandler::BuildAndSendSyncStatus() {
@@ -116,14 +129,11 @@ void NewTabPageSyncHandler::BuildAndSendSyncStatus() {
// We show the sync promotion if sync has not been enabled and the user is
// logged in to Google Accounts. If the user is not signed in to GA, we
// should hide the sync status section entirely.
- if (!sync_service_->HasSyncSetupCompleted() &&
- !sync_service_->SetupInProgress()) {
- if (IsGoogleGAIACookieInstalled()) {
- SendSyncMessageToPage(SyncStatusUIHelper::PRE_SYNCED,
+ if (!sync_service_->HasSyncSetupCompleted()) {
+ if(!sync_service_->SetupInProgress() && IsGoogleGAIACookieInstalled()) {
+ SendSyncMessageToPage(PROMOTION,
WideToUTF8(l10n_util::GetString(IDS_SYNC_NTP_PROMOTION_MESSAGE)),
WideToUTF8(l10n_util::GetString(IDS_SYNC_NTP_START_NOW_LINK_LABEL)));
- } else {
- HideSyncStatusSection();
}
return;
}
@@ -131,17 +141,15 @@ void NewTabPageSyncHandler::BuildAndSendSyncStatus() {
// Once sync has been enabled, the supported "sync statuses" for the NNTP
// from the user's perspective are:
//
- // "Synced to foo@gmail.com", when we are successfully authenticated and
- // connected to a sync server.
// "Sync error", when we can't authenticate or establish a connection with
// the sync server (appropriate information appended to
// message).
- // "Authenticating", when credentials are in flight.
- SyncStatusUIHelper::MessageType type(SyncStatusUIHelper::PRE_SYNCED);
std::wstring status_msg;
std::wstring link_text;
- type = SyncStatusUIHelper::GetLabels(sync_service_, &status_msg, &link_text);
- SendSyncMessageToPage(type, WideToUTF8(status_msg), WideToUTF8(link_text));
+ SyncStatusUIHelper::MessageType type =
+ SyncStatusUIHelper::GetLabels(sync_service_, &status_msg, &link_text);
+ SendSyncMessageToPage(FromSyncStatusMessageType(type),
+ WideToUTF8(status_msg), WideToUTF8(link_text));
}
void NewTabPageSyncHandler::HandleSyncLinkClicked(const Value* value) {
@@ -165,7 +173,7 @@ void NewTabPageSyncHandler::OnStateChanged() {
}
void NewTabPageSyncHandler::SendSyncMessageToPage(
- SyncStatusUIHelper::MessageType type, std::string msg,
+ MessageType type, std::string msg,
std::string linktext) {
DictionaryValue value;
std::string msgtype;
@@ -174,28 +182,24 @@ void NewTabPageSyncHandler::SendSyncMessageToPage(
WideToUTF8(l10n_util::GetString(IDS_SYNC_NTP_SYNC_SECTION_TITLE));
std::string linkurl;
switch (type) {
- case SyncStatusUIHelper::PRE_SYNCED:
+ case HIDE:
+ case PROMOTION:
msgtype = "presynced";
break;
- case SyncStatusUIHelper::SYNCED:
- msgtype = "synced";
- linktext =
- WideToUTF8(l10n_util::GetString(IDS_SYNC_NTP_VIEW_ONLINE_LINK));
- linkurl = kSyncDefaultViewOnlineUrl;
- user = UTF16ToWide(sync_service_->GetAuthenticatedUsername());
- msg = WideToUTF8(l10n_util::GetStringF(IDS_SYNC_NTP_SYNCED_TO, user));
- break;
- case SyncStatusUIHelper::SYNC_ERROR:
+ case SYNC_ERROR:
title =
WideToUTF8(
l10n_util::GetString(IDS_SYNC_NTP_SYNC_SECTION_ERROR_TITLE));
msgtype = "error";
break;
+ default:
+ NOTREACHED();
+ break;
}
// If there is no message to show, we should hide the sync section
// altogether.
- if (msg.empty()) {
+ if (type == HIDE || msg.empty()) {
value.SetBoolean(L"syncsectionisvisible", false);
} else {
value.SetBoolean(L"syncsectionisvisible", true);
diff --git a/chrome/browser/dom_ui/new_tab_page_sync_handler.h b/chrome/browser/dom_ui/new_tab_page_sync_handler.h
index 5931684..9774640 100644
--- a/chrome/browser/dom_ui/new_tab_page_sync_handler.h
+++ b/chrome/browser/dom_ui/new_tab_page_sync_handler.h
@@ -36,8 +36,13 @@ class NewTabPageSyncHandler : public DOMMessageHandler,
virtual void OnStateChanged();
private:
+ enum MessageType {
+ HIDE,
+ PROMOTION,
+ SYNC_ERROR,
+ };
// Helper to invoke the |syncMessageChanged| JS function on the new tab page.
- void SendSyncMessageToPage(SyncStatusUIHelper::MessageType type,
+ void SendSyncMessageToPage(MessageType type,
std::string msg, std::string linktext);
// Helper to query the sync service and figure out what to send to
@@ -48,6 +53,10 @@ class NewTabPageSyncHandler : public DOMMessageHandler,
// Helper to send a message to the NNTP which hides the sync section.
void HideSyncStatusSection();
+ // Helper to convert from a sync status message type to an NTP specific one.
+ static MessageType FromSyncStatusMessageType(
+ SyncStatusUIHelper::MessageType type);
+
// Cached pointer to ProfileSyncService.
ProfileSyncService* sync_service_;
diff --git a/chrome/browser/resources/new_new_tab.js b/chrome/browser/resources/new_new_tab.js
index a130105..7c98c21 100644
--- a/chrome/browser/resources/new_new_tab.js
+++ b/chrome/browser/resources/new_new_tab.js
@@ -728,6 +728,7 @@ function syncMessageChanged(newMessage) {
// Hide the section if the message is emtpy.
if (!newMessage.syncsectionisvisible) {
+ style.display = 'none';
return;
}
style.display = 'block';
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index 3dbf1d7..2efba68 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -212,9 +212,9 @@ void ProfileSyncService::UpdateLastSyncedTime() {
void ProfileSyncService::OnUnrecoverableError() {
unrecoverable_error_detected_ = true;
change_processor_->Stop();
-
- if (SetupInProgress())
- wizard_.Step(SyncSetupWizard::FATAL_ERROR);
+
+ // Tell the wizard so it can inform the user only if it is already open.
+ wizard_.Step(SyncSetupWizard::FATAL_ERROR);
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
LOG(ERROR) << "Unrecoverable error detected -- ProfileSyncService unusable.";
}
@@ -338,17 +338,19 @@ void ProfileSyncService::OnUserSubmittedAuth(
void ProfileSyncService::OnUserAcceptedMergeAndSync() {
base::TimeTicks start_time = base::TimeTicks::Now();
+ bool not_first_run = model_associator_->SyncModelHasUserCreatedNodes();
bool merge_success = model_associator_->AssociateModels();
UMA_HISTOGRAM_MEDIUM_TIMES("Sync.UserPerceivedBookmarkAssociation",
base::TimeTicks::Now() - start_time);
-
- wizard_.Step(SyncSetupWizard::DONE); // TODO(timsteele): error state?
if (!merge_success) {
LOG(ERROR) << "Model assocation failed.";
OnUnrecoverableError();
return;
}
+ wizard_.Step(not_first_run ? SyncSetupWizard::DONE :
+ SyncSetupWizard::DONE_FIRST_TIME);
+
change_processor_->Start(profile_->GetBookmarkModel(),
backend_->GetUserShareHandle());
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
@@ -385,17 +387,19 @@ void ProfileSyncService::StartProcessingChangesIfReady() {
// We're ready to merge the models.
base::TimeTicks start_time = base::TimeTicks::Now();
+ bool not_first_run = model_associator_->SyncModelHasUserCreatedNodes();
bool merge_success = model_associator_->AssociateModels();
UMA_HISTOGRAM_TIMES("Sync.BookmarkAssociationTime",
base::TimeTicks::Now() - start_time);
-
- wizard_.Step(SyncSetupWizard::DONE); // TODO(timsteele): error state?
if (!merge_success) {
- LOG(ERROR) << "Model assocation failed.";
- OnUnrecoverableError();
- return;
+ LOG(ERROR) << "Model assocation failed.";
+ OnUnrecoverableError();
+ return;
}
+ wizard_.Step(not_first_run ? SyncSetupWizard::DONE :
+ SyncSetupWizard::DONE_FIRST_TIME);
+
change_processor_->Start(profile_->GetBookmarkModel(),
backend_->GetUserShareHandle());
FOR_EACH_OBSERVER(Observer, observers_, OnStateChanged());
diff --git a/chrome/browser/sync/resources/gaia_login.html b/chrome/browser/sync/resources/gaia_login.html
index 478dce7..7f16c7c 100644
--- a/chrome/browser/sync/resources/gaia_login.html
+++ b/chrome/browser/sync/resources/gaia_login.html
@@ -34,6 +34,9 @@
text-align: left;
margin: 5px;
}
+ #gaia_loginform {
+ margin-bottom: 0.5em;
+ }
--></style>
</head>
<body bgcolor="#ffffff" vlink="#666666"
@@ -190,8 +193,8 @@
</div>
<form id="gaia_loginform" onsubmit="sendCredentialsAndClose(); return false;">
<div id="gaia_loginbox">
-<table class="form-noindent" cellspacing="3" cellpadding="5" width="100%"
- border="0">
+<table class="form-noindent" cellspacing="3" cellpadding="5" width="75%"
+ border="0" align="center">
<tr>
<td valign="top" style="text-align:center" nowrap="nowrap"
bgcolor="#e8eefa">
@@ -313,7 +316,8 @@
<td>
<input id="signIn" type="button" class="gaia le button"
name="signIn" i18n-values="value:signin"
- onclick="sendCredentialsAndClose();" />
+ onclick="sendCredentialsAndClose();"
+ style="width:85" />
</td>
</tr>
</table>
@@ -346,7 +350,8 @@
</tr>
</table>
<div class="endaligned">
- <input type="button" name="cancel" i18n-values="value:cancel" onclick="CloseDialog();"/>
+ <input type="button" name="cancel" i18n-values="value:cancel"
+ onclick="CloseDialog();" style="width:85" />
</div>
</body>
</html>
diff --git a/chrome/browser/sync/resources/merge_and_sync.html b/chrome/browser/sync/resources/merge_and_sync.html
index 8af2fc1..f350ae0 100644
--- a/chrome/browser/sync/resources/merge_and_sync.html
+++ b/chrome/browser/sync/resources/merge_and_sync.html
@@ -3,8 +3,20 @@
<title></title>
<style type="text/css">
body,td,div,p,a,font,span {font-family: arial,sans-serif;}
- body { bgcolor:"#ffffff" }
+ body { bgcolor:"#ffffff" }
.gaia.le.button { font-family: Arial, Helvetica, sans-serif; font-size: smaller; }
+.endaligned {
+ text-align: right;
+}
+html[dir='rtl'] .endaligned {
+ text-align: left;
+}
+.textaligned {
+ text-align: left;
+}
+html[dir='rtl'] .textaligned {
+ text-align: right;
+}
</style>
<script>
function advanceThrobber() {
@@ -12,18 +24,18 @@
throbber.style.backgroundPositionX =
((parseInt(throbber.style.backgroundPositionX) - 16) % 576) + 'px';
}
-
+
function acceptMergeAndSync() {
var throbber = document.getElementById('throbber_container');
throbber.style.display = "inline";
document.getElementById("acceptMerge").disabled = true;
chrome.send("SubmitMergeAndSync", [""]);
}
-
+
function Close() {
chrome.send("DialogClose", [""]);
}
-
+
function showMergeAndSyncDone() {
var throbber = document.getElementById('throbber_container');
throbber.style.display = "none";
@@ -33,7 +45,7 @@
document.getElementById("close").value = templateData['closelabel'];
setTimeout(Close, 1600);
}
-
+
function showMergeAndSyncError() {
var throbber = document.getElementById('throbber_container');
throbber.style.display = "none";
@@ -41,36 +53,37 @@
"<p><font size='-1'><b>" + templateData['setuperror']
+ "</b></font></p>";
}
-
+
</script>
</head>
<body onload="setInterval(advanceThrobber, 30);">
-<div id="header">
- <p><font size="-1"><b><span i18n-content="introduction"></span></b>
- </font></p>
-</div>
-<br />
-<img src="merge_and_sync.png" i18n-values="alt:mergeandsynclabel" />
-<br />
-<p><font size="-1"><span i18n-content="mergeandsyncwarning"></span></font></p>
-<br />
-<table align="right">
- <tr>
- <td>
+<table height="100%">
+ <tr valign="top">
+ <td align="center">
+ <div id="header" align="left">
+ <p class="textaligned"><font size="-1"><b>
+ <span i18n-content="introduction"></span>
+ </b></font></p>
+ </div>
+ <br />
+ <img src="merge_and_sync.png" i18n-values="alt:mergeandsynclabel" />
+ <br />
+ <p class="textaligned"><font size="-1"><span i18n-content="mergeandsyncwarning"></span></font></p>
+ <br />
<div id="throbber_container" style="display:none">
<div id="throb" style="background-image:url(throbber.png);
width:16px; height:16px; background-position:0px;">
</div>
</div>
</td>
- <td>
+ </tr>
+ <tr class="endaligned" valign="bottom">
+ <td class="endaligned">
<input id="acceptMerge" type="button" class="gaia le button" name="accept"
i18n-values="value:mergeandsynclabel"
onclick="acceptMergeAndSync();" />
- </td>
- <td>
<input id="close" type="button" i18n-values="value:abortlabel"
- onclick="Close();"/>
+ onclick="Close();" style="width:85"/>
</td>
</tr>
</table>
diff --git a/chrome/browser/sync/resources/setup_done.html b/chrome/browser/sync/resources/setup_done.html
new file mode 100644
index 0000000..897f191
--- /dev/null
+++ b/chrome/browser/sync/resources/setup_done.html
@@ -0,0 +1,59 @@
+<html i18n-values="dir:textdirection;">
+<head>
+<title></title>
+<style type="text/css">
+body,td,div,p,a,font,span {
+ font-family: arial,sans-serif;
+ }
+body {
+ bgcolor:"#ffffff"
+ }
+.gaia.le.button {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: smaller;
+}
+.endaligned {
+ text-align: right;
+ align: right;
+}
+html[dir='rtl'] .endaligned {
+ text-align: left;
+ align: left;
+}
+</style>
+<script>
+ function setShowFirstTimeSetupSummary() {
+ document.getElementById("summary").innerHTML =
+ "<p><font size='-1'>" + templateData['firsttimesetupsummary']
+ + "</font></p>";
+ }
+ function setSyncedToUser(synced_to) {
+ document.getElementById('user').innerHTML = synced_to;
+ }
+</script>
+<body bgcolor="#ffffff" vlink="#666666
+ i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize"
+ style="margin: 10px">
+<table height="100%" width="100%" margin="0" cellpadding="0">
+ <tr valign="top">
+ <td>
+ <p><font size="-1"><b><span i18n-content="success"></span></b></font></p>
+ <div align="center">
+ <img src="success-large.png" />
+ </div>
+ <br />
+ <p><font size="-1"><span id="user"></span></font></p>
+ <div id="summary">
+ <p><font size="-1"><span i18n-content="setupsummary"></span></font></p>
+ </div>
+ </td>
+ </tr>
+ <tr valign="bottom">
+ <td class="endaligned">
+ <input id="close" type="submit" i18n-values="value:okay" style="width:85"
+ onclick='chrome.send("DialogClose", [""])' />
+ </td>
+ </tr>
+</table>
+</body>
+</html>
diff --git a/chrome/browser/sync/resources/setup_flow.html b/chrome/browser/sync/resources/setup_flow.html
index f818787..9bec21a 100644
--- a/chrome/browser/sync/resources/setup_flow.html
+++ b/chrome/browser/sync/resources/setup_flow.html
@@ -8,6 +8,11 @@
document.getElementById("login").style.display = "none";
document.getElementById("merge").style.display = "block";
}
+ function showSetupDone() {
+ document.getElementById("login").style.display = "none";
+ document.getElementById("merge").style.display = "none";
+ document.getElementById("done").style.display = "block";
+ }
</script>
</HEAD>
<BODY style="margin:0; border:0;">
@@ -15,5 +20,7 @@
src="chrome://syncresources/gaialogin"></iframe>
<iframe id="merge" frameborder="0" width="100%" scrolling="no" height="100%"
src="chrome://syncresources/mergeandsync" style="display:none"></iframe>
+ <iframe id="done" frameborder="0" width="100%" scrolling="no" height="100%"
+ src="chrome://syncresources/setupdone" style="display:none"></iframe>
</BODY>
</HTML>
diff --git a/chrome/browser/views/confirm_message_box_dialog.cc b/chrome/browser/views/confirm_message_box_dialog.cc
index fe66582..6182bd8 100644
--- a/chrome/browser/views/confirm_message_box_dialog.cc
+++ b/chrome/browser/views/confirm_message_box_dialog.cc
@@ -25,11 +25,38 @@ void ConfirmMessageBoxDialog::Run(gfx::NativeWindow parent,
window->Show();
}
+// static
+void ConfirmMessageBoxDialog::RunWithCustomConfiguration(
+ gfx::NativeWindow parent,
+ ConfirmMessageBoxObserver* observer,
+ const std::wstring& message_text,
+ const std::wstring& window_title,
+ const std::wstring& confirm_label,
+ const std::wstring& reject_label,
+ const gfx::Size& preferred_size) {
+ DCHECK(observer);
+ ConfirmMessageBoxDialog* dialog = new ConfirmMessageBoxDialog(observer,
+ message_text, window_title);
+ dialog->preferred_size_ = preferred_size;
+ dialog->confirm_label_ = confirm_label;
+ dialog->reject_label_ = reject_label;
+ views::Window* window = views::Window::CreateChromeWindow(
+ parent, gfx::Rect(), dialog);
+ window->Show();
+}
+
ConfirmMessageBoxDialog::ConfirmMessageBoxDialog(
ConfirmMessageBoxObserver* observer, const std::wstring& message_text,
const std::wstring& window_title)
: observer_(observer),
- window_title_(window_title) {
+ window_title_(window_title),
+ preferred_size_(gfx::Size(views::Window::GetLocalizedContentsSize(
+ IDS_CONFIRM_MESSAGE_BOX_DEFAULT_WIDTH_CHARS,
+ IDS_CONFIRM_MESSAGE_BOX_DEFAULT_HEIGHT_LINES))),
+ confirm_label_(l10n_util::GetString(
+ IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL)),
+ reject_label_(l10n_util::GetString(
+ IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL)) {
message_label_ = new views::Label(message_text);
message_label_->SetMultiLine(true);
l10n_util::TextDirection direction =
@@ -59,10 +86,10 @@ std::wstring ConfirmMessageBoxDialog::GetWindowTitle() const {
std::wstring ConfirmMessageBoxDialog::GetDialogButtonLabel(
MessageBoxFlags::DialogButton button) const {
if (button == MessageBoxFlags::DIALOGBUTTON_OK) {
- return l10n_util::GetString(IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL);
+ return confirm_label_;
}
if (button == MessageBoxFlags::DIALOGBUTTON_CANCEL)
- return l10n_util::GetString(IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL);
+ return reject_label_;
return DialogDelegate::GetDialogButtonLabel(button);
}
@@ -84,7 +111,5 @@ void ConfirmMessageBoxDialog::Layout() {
}
gfx::Size ConfirmMessageBoxDialog::GetPreferredSize() {
- return gfx::Size(views::Window::GetLocalizedContentsSize(
- IDS_CONFIRM_MESSAGE_BOX_DEFAULT_WIDTH_CHARS,
- IDS_CONFIRM_MESSAGE_BOX_DEFAULT_HEIGHT_LINES));
+ return preferred_size_;
} \ No newline at end of file
diff --git a/chrome/browser/views/confirm_message_box_dialog.h b/chrome/browser/views/confirm_message_box_dialog.h
index b2ca806..81c0213 100644
--- a/chrome/browser/views/confirm_message_box_dialog.h
+++ b/chrome/browser/views/confirm_message_box_dialog.h
@@ -28,18 +28,28 @@ class ConfirmMessageBoxDialog : public views::DialogDelegate,
public views::View {
public:
// The method presents a modal confirmation dialog to the user with the title
- // |window_title| and message |message_text|. |observer| will be notified
- // when the user makes a decision or closes the dialog. Note that this class
- // guarantees it will call one of the observer's methods, so it is the
- // caller's responsibility to ensure |observer| lives until one of the
- // methods is invoked; it can be deleted thereafter from this class' point
- // of view. |parent| specifies where to insert the view into the hierarchy
- // and effectively assumes ownership of the dialog.
+ // |window_title| and message |message_text|, and 'Yes' 'No' buttons.
+ // |observer| will be notified when the user makes a decision or closes the
+ // dialog. Note that this class guarantees it will call one of the observer's
+ // methods, so it is the caller's responsibility to ensure |observer| lives
+ // until one of the methods is invoked; it can be deleted thereafter from this
+ // class' point of view. |parent| specifies where to insert the view into the
+ // hierarchy and effectively assumes ownership of the dialog.
static void Run(gfx::NativeWindow parent,
ConfirmMessageBoxObserver* observer,
const std::wstring& message_text,
const std::wstring& window_title);
+ // A variant of the above for when the message text is longer/shorter than
+ // what the default size of this dialog can accommodate.
+ static void RunWithCustomConfiguration(gfx::NativeWindow parent,
+ ConfirmMessageBoxObserver* observer,
+ const std::wstring& message_text,
+ const std::wstring& window_title,
+ const std::wstring& confirm_label,
+ const std::wstring& reject_label,
+ const gfx::Size& preferred_size);
+
virtual ~ConfirmMessageBoxDialog() {}
// views::DialogDelegate implementation.
@@ -47,6 +57,10 @@ class ConfirmMessageBoxDialog : public views::DialogDelegate,
virtual std::wstring GetWindowTitle() const;
virtual std::wstring GetDialogButtonLabel(
MessageBoxFlags::DialogButton button) const;
+ virtual int GetDefaultDialogButton() const {
+ return MessageBoxFlags::DIALOGBUTTON_CANCEL;
+ }
+
virtual bool Accept();
virtual bool Cancel();
@@ -69,6 +83,13 @@ class ConfirmMessageBoxDialog : public views::DialogDelegate,
// This is the Title bar text.
std::wstring window_title_;
+ // The text for the 'OK' and 'CANCEL' buttons.
+ std::wstring confirm_label_;
+ std::wstring reject_label_;
+
+ // The preferred size of the dialog.
+ gfx::Size preferred_size_;
+
// The observer to notify of acceptance or cancellation.
ConfirmMessageBoxObserver* observer_;
diff --git a/chrome/browser/views/options/content_page_view.cc b/chrome/browser/views/options/content_page_view.cc
index 2f8efb0..a3df28c 100644
--- a/chrome/browser/views/options/content_page_view.cc
+++ b/chrome/browser/views/options/content_page_view.cc
@@ -128,9 +128,19 @@ void ContentPageView::ButtonPressed(
#ifdef CHROME_PERSONALIZATION
} else if (sender == sync_start_stop_button_) {
DCHECK(sync_service_);
+
if (sync_service_->HasSyncSetupCompleted()) {
- sync_service_->DisableForUser();
- ProfileSyncService::SyncEvent(ProfileSyncService::STOP_FROM_OPTIONS);
+ ConfirmMessageBoxDialog::RunWithCustomConfiguration(
+ GetWindow()->GetNativeWindow(),
+ this,
+ l10n_util::GetString(IDS_SYNC_STOP_SYNCING_EXPLANATION_LABEL),
+ l10n_util::GetString(IDS_SYNC_STOP_SYNCING_BUTTON_LABEL),
+ l10n_util::GetString(IDS_SYNC_STOP_SYNCING_CONFIRM_BUTTON_LABEL),
+ l10n_util::GetString(IDS_CANCEL),
+ gfx::Size(views::Window::GetLocalizedContentsSize(
+ IDS_CONFIRM_STOP_SYNCING_DIALOG_WIDTH_CHARS,
+ IDS_CONFIRM_STOP_SYNCING_DIALOG_HEIGHT_LINES)));
+ return;
} else {
sync_service_->EnableForUser();
ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_OPTIONS);
@@ -422,6 +432,11 @@ void ContentPageView::InitBrowsingDataGroup() {
L"", true);
}
+void ContentPageView::OnConfirmMessageAccept() {
+ sync_service_->DisableForUser();
+ ProfileSyncService::SyncEvent(ProfileSyncService::STOP_FROM_OPTIONS);
+}
+
#ifdef CHROME_PERSONALIZATION
void ContentPageView::InitSyncGroup() {
sync_status_label_ = new views::Label;
diff --git a/chrome/browser/views/options/content_page_view.h b/chrome/browser/views/options/content_page_view.h
index 62133c0..e3902c4 100644
--- a/chrome/browser/views/options/content_page_view.h
+++ b/chrome/browser/views/options/content_page_view.h
@@ -7,6 +7,7 @@
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/views/options/options_page_view.h"
+#include "chrome/browser/views/confirm_message_box_dialog.h"
#include "chrome/common/pref_member.h"
#include "views/controls/button/button.h"
#include "views/controls/link.h"
@@ -30,7 +31,8 @@ class ContentPageView : public OptionsPageView,
public views::LinkController,
public ProfileSyncServiceObserver,
#endif
- public views::ButtonListener {
+ public views::ButtonListener,
+ public ConfirmMessageBoxObserver {
public:
explicit ContentPageView(Profile* profile);
virtual ~ContentPageView();
@@ -41,6 +43,9 @@ class ContentPageView : public OptionsPageView,
// views::LinkController method.
virtual void LinkActivated(views::Link* source, int event_flags);
+ // ConfirmMessageBoxObserver implementation.
+ virtual void OnConfirmMessageAccept();
+
#ifdef CHROME_PERSONALIZATION
// ProfileSyncServiceObserver method.
virtual void OnStateChanged();
diff --git a/chrome/browser/views/sync/sync_setup_flow.cc b/chrome/browser/views/sync/sync_setup_flow.cc
index 7019c39..01a5728 100644
--- a/chrome/browser/views/sync/sync_setup_flow.cc
+++ b/chrome/browser/views/sync/sync_setup_flow.cc
@@ -25,6 +25,7 @@
// XPath expression for finding specific iframes.
static const wchar_t* kLoginIFrameXPath = L"//iframe[@id='login']";
static const wchar_t* kMergeIFrameXPath = L"//iframe[@id='merge']";
+static const wchar_t* kDoneIframeXPath = L"//iframe[@id='done']";
// Helper function to read the JSON string from the Value parameter.
static std::string GetJsonResponse(const Value* content) {
@@ -114,8 +115,23 @@ void FlowHandler::ShowMergeAndSync() {
dom_ui_->CallJavascriptFunction(L"showMergeAndSync");
}
-void FlowHandler::ShowMergeAndSyncDone() {
- ExecuteJavascriptInIFrame(kMergeIFrameXPath, L"showMergeAndSyncDone();");
+void FlowHandler::ShowSetupDone(const std::wstring& user) {
+ StringValue synced_to_string(WideToUTF8(l10n_util::GetStringF(
+ IDS_SYNC_NTP_SYNCED_TO, user)));
+ std::string json;
+ JSONWriter::Write(&synced_to_string, false, &json);
+ std::wstring javascript = std::wstring(L"setSyncedToUser") +
+ L"(" + UTF8ToWide(json) + L");";
+ ExecuteJavascriptInIFrame(kDoneIframeXPath, javascript);
+
+ if (dom_ui_)
+ dom_ui_->CallJavascriptFunction(L"showSetupDone", synced_to_string);
+}
+
+void FlowHandler::ShowFirstTimeDone(const std::wstring& user) {
+ ExecuteJavascriptInIFrame(kDoneIframeXPath,
+ L"setShowFirstTimeSetupSummary();");
+ ShowSetupDone(user);
}
void FlowHandler::ShowMergeAndSyncError() {
@@ -153,7 +169,8 @@ void SyncSetupFlow::GetDialogSize(gfx::Size* size) const {
void SyncSetupFlow::OnDialogClosed(const std::string& json_retval) {
DCHECK(json_retval.empty());
container_->set_flow(NULL); // Sever ties from the wizard.
- if (current_state_ == SyncSetupWizard::DONE) {
+ if (current_state_ == SyncSetupWizard::DONE ||
+ current_state_ == SyncSetupWizard::DONE_FIRST_TIME) {
service_->SetSyncSetupCompleted();
}
@@ -171,6 +188,7 @@ void SyncSetupFlow::OnDialogClosed(const std::string& json_retval) {
ProfileSyncService::SyncEvent(
ProfileSyncService::CANCEL_DURING_SIGNON_AFTER_MERGE);
break;
+ case SyncSetupWizard::DONE_FIRST_TIME:
case SyncSetupWizard::DONE:
UMA_HISTOGRAM_MEDIUM_TIMES("Sync.UserPerceivedAuthorizationTime",
base::TimeTicks::Now() - login_start_time_);
@@ -212,6 +230,7 @@ bool SyncSetupFlow::ShouldAdvance(SyncSetupWizard::State state) {
return current_state_ == SyncSetupWizard::GAIA_SUCCESS;
case SyncSetupWizard::FATAL_ERROR:
return true; // You can always hit the panic button.
+ case SyncSetupWizard::DONE_FIRST_TIME:
case SyncSetupWizard::DONE:
return current_state_ == SyncSetupWizard::MERGE_AND_SYNC ||
current_state_ == SyncSetupWizard::GAIA_SUCCESS;
@@ -244,11 +263,11 @@ void SyncSetupFlow::Advance(SyncSetupWizard::State advance_state) {
if (current_state_ == SyncSetupWizard::MERGE_AND_SYNC)
flow_handler_->ShowMergeAndSyncError();
break;
+ case SyncSetupWizard::DONE_FIRST_TIME:
+ flow_handler_->ShowFirstTimeDone(service_->GetAuthenticatedUsername());
+ break;
case SyncSetupWizard::DONE:
- if (current_state_ == SyncSetupWizard::MERGE_AND_SYNC)
- flow_handler_->ShowMergeAndSyncDone();
- else if (current_state_ == SyncSetupWizard::GAIA_SUCCESS)
- flow_handler_->ShowGaiaSuccessAndClose();
+ flow_handler_->ShowSetupDone(service_->GetAuthenticatedUsername());
break;
default:
NOTREACHED() << "Invalid advance state: " << advance_state;
diff --git a/chrome/browser/views/sync/sync_setup_flow.h b/chrome/browser/views/sync/sync_setup_flow.h
index f02b292..4bc7d60 100644
--- a/chrome/browser/views/sync/sync_setup_flow.h
+++ b/chrome/browser/views/sync/sync_setup_flow.h
@@ -170,8 +170,9 @@ class FlowHandler : public DOMMessageHandler {
void ShowGaiaSuccessAndClose();
void ShowGaiaSuccessAndSettingUp();
void ShowMergeAndSync();
- void ShowMergeAndSyncDone();
void ShowMergeAndSyncError();
+ void ShowSetupDone(const std::wstring& user);
+ void ShowFirstTimeDone(const std::wstring& user);
void set_flow(SyncSetupFlow* flow) {
flow_ = flow;
diff --git a/chrome/browser/views/sync/sync_setup_wizard.cc b/chrome/browser/views/sync/sync_setup_wizard.cc
index 5e46382..31afcea 100644
--- a/chrome/browser/views/sync/sync_setup_wizard.cc
+++ b/chrome/browser/views/sync/sync_setup_wizard.cc
@@ -80,7 +80,7 @@ void SyncResourcesSource::StartDataRequest(const std::string& path_raw,
localized_strings.SetString(L"settingup",
l10n_util::GetString(IDS_SYNC_LOGIN_SETTING_UP));
localized_strings.SetString(L"success",
- l10n_util::GetString(IDS_SYNC_LOGIN_SUCCESS));
+ l10n_util::GetString(IDS_SYNC_SUCCESS));
localized_strings.SetString(L"errorsigningin",
l10n_util::GetString(IDS_SYNC_ERROR_SIGNING_IN));
static const base::StringPiece html(ResourceBundle::GetSharedInstance()
@@ -98,8 +98,6 @@ void SyncResourcesSource::StartDataRequest(const std::string& path_raw,
l10n_util::GetString(IDS_ABORT));
localized_strings.SetString(L"closelabel",
l10n_util::GetString(IDS_CLOSE));
- localized_strings.SetString(L"alldone",
- l10n_util::GetString(IDS_SYNC_MERGE_ALL_DONE));
localized_strings.SetString(L"mergeandsyncwarning",
l10n_util::GetString(IDS_SYNC_MERGE_WARNING));
localized_strings.SetString(L"setuperror",
@@ -110,6 +108,21 @@ void SyncResourcesSource::StartDataRequest(const std::string& path_raw,
SetFontAndTextDirection(&localized_strings);
response = jstemplate_builder::GetI18nTemplateHtml(
html, &localized_strings);
+ } else if (path_raw == chrome::kSyncSetupDonePath) {
+ DictionaryValue localized_strings;
+ localized_strings.SetString(L"success",
+ l10n_util::GetString(IDS_SYNC_SUCCESS));
+ localized_strings.SetString(L"setupsummary",
+ l10n_util::GetString(IDS_SYNC_SETUP_ALL_DONE));
+ localized_strings.SetString(L"firsttimesetupsummary",
+ l10n_util::GetString(IDS_SYNC_SETUP_FIRST_TIME_ALL_DONE));
+ localized_strings.SetString(L"okay",
+ l10n_util::GetString(IDS_SYNC_SETUP_OK_BUTTON_LABEL));
+ static const base::StringPiece html(ResourceBundle::GetSharedInstance()
+ .GetRawDataResource(IDR_SYNC_SETUP_DONE_HTML));
+ SetFontAndTextDirection(&localized_strings);
+ response = jstemplate_builder::GetI18nTemplateHtml(
+ html, &localized_strings);
} else if (path_raw == chrome::kSyncSetupFlowPath) {
static const base::StringPiece html(ResourceBundle::GetSharedInstance()
.GetRawDataResource(IDR_SYNC_SETUP_FLOW_HTML));
@@ -146,7 +159,7 @@ void SyncSetupWizard::Step(State advance_state) {
flow->Advance(advance_state);
} else if (!service_->profile()->GetPrefs()->GetBoolean(
prefs::kSyncHasSetupCompleted)) {
- if (advance_state == DONE || advance_state == GAIA_SUCCESS)
+ if (IsTerminalState(advance_state))
return;
// No flow is in progress, and we have never escorted the user all the
// way through the wizard flow.
@@ -155,13 +168,21 @@ void SyncSetupWizard::Step(State advance_state) {
} else {
// No flow in in progress, but we've finished the wizard flow once before.
// This is just a discrete run.
- if (advance_state == DONE || advance_state == GAIA_SUCCESS)
+ if (IsTerminalState(advance_state))
return; // Nothing to do.
flow_container_->set_flow(SyncSetupFlow::Run(service_, flow_container_,
advance_state, GetEndStateForDiscreteRun(advance_state)));
}
}
+// static
+bool SyncSetupWizard::IsTerminalState(State advance_state) {
+ return advance_state == GAIA_SUCCESS ||
+ advance_state == DONE ||
+ advance_state == DONE_FIRST_TIME ||
+ advance_state == FATAL_ERROR;
+}
+
bool SyncSetupWizard::IsVisible() const {
return flow_container_->get_flow() != NULL;
}
diff --git a/chrome/browser/views/sync/sync_setup_wizard.h b/chrome/browser/views/sync/sync_setup_wizard.h
index f51ba64..1d36f61 100644
--- a/chrome/browser/views/sync/sync_setup_wizard.h
+++ b/chrome/browser/views/sync/sync_setup_wizard.h
@@ -19,10 +19,23 @@ class ProfileSyncService;
class SyncSetupWizard {
public:
enum State {
+ // Show the Google Account login UI.
GAIA_LOGIN = 0,
+ // A login attempt succeeded. Depending on initial conditions, this may
+ // cause a transition to DONE, or to wait for an explicit transition (via
+ // Step) to the next state.
GAIA_SUCCESS,
+ // The user needs to accept a merge and sync warning to proceed.
MERGE_AND_SYNC,
+ // The panic switch. Something went terribly wrong during setup and we
+ // can't recover.
FATAL_ERROR,
+ // A final state for when setup completes and it is possible it is the
+ // user's first time (globally speaking) as the cloud doesn't have any
+ // bookmarks. We show additional info in this case to explain setting up
+ // more computers.
+ DONE_FIRST_TIME,
+ // A catch-all done case for any setup process.
DONE
};
@@ -51,6 +64,9 @@ class SyncSetupWizard {
// the end state to pass to Run for a given |start_state|.
static State GetEndStateForDiscreteRun(State start_state);
+ // Helper to return whether |state| warrants starting a new flow.
+ static bool IsTerminalState(State state);
+
ProfileSyncService* service_;
#if defined(OS_WIN)
diff --git a/chrome/browser/views/sync/sync_setup_wizard_unittest.cc b/chrome/browser/views/sync/sync_setup_wizard_unittest.cc
index 4861649..fec7ef3 100644
--- a/chrome/browser/views/sync/sync_setup_wizard_unittest.cc
+++ b/chrome/browser/views/sync/sync_setup_wizard_unittest.cc
@@ -254,10 +254,11 @@ TEST_F(SyncSetupWizardTest, InitialStepMergeAndSync) {
EXPECT_TRUE(service_->user_accepted_merge_and_sync_);
EXPECT_FALSE(service_->user_cancelled_dialog_);
service_->ResetTestStats();
- wizard_->Step(SyncSetupWizard::DONE); // No merge and sync.
+ wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME); // No merge and sync.
EXPECT_TRUE(wizard_->IsVisible());
EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled());
- EXPECT_EQ(SyncSetupWizard::DONE, test_window_->flow()->current_state_);
+ EXPECT_EQ(SyncSetupWizard::DONE_FIRST_TIME,
+ test_window_->flow()->current_state_);
}
TEST_F(SyncSetupWizardTest, DialogCancelled) {
@@ -294,12 +295,18 @@ TEST_F(SyncSetupWizardTest, InvalidTransitions) {
EXPECT_FALSE(wizard_->IsVisible());
EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled());
+ wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME);
+ EXPECT_FALSE(wizard_->IsVisible());
+ EXPECT_FALSE(test_window_->TestAndResetWasShowHTMLDialogCalled());
+
wizard_->Step(SyncSetupWizard::GAIA_LOGIN);
wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC);
EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_);
wizard_->Step(SyncSetupWizard::DONE);
EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_);
+ wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME);
+ EXPECT_EQ(SyncSetupWizard::GAIA_LOGIN, test_window_->flow()->current_state_);
wizard_->Step(SyncSetupWizard::GAIA_SUCCESS);
wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC);
@@ -325,6 +332,17 @@ TEST_F(SyncSetupWizardTest, FullSuccessfulRunSetsPref) {
prefs::kSyncHasSetupCompleted));
}
+TEST_F(SyncSetupWizardTest, FirstFullSuccessfulRunSetsPref) {
+ wizard_->Step(SyncSetupWizard::GAIA_LOGIN);
+ wizard_->Step(SyncSetupWizard::GAIA_SUCCESS);
+ wizard_->Step(SyncSetupWizard::MERGE_AND_SYNC);
+ wizard_->Step(SyncSetupWizard::DONE_FIRST_TIME);
+ test_window_->CloseDialog();
+ EXPECT_FALSE(wizard_->IsVisible());
+ EXPECT_TRUE(service_->profile()->GetPrefs()->GetBoolean(
+ prefs::kSyncHasSetupCompleted));
+}
+
TEST_F(SyncSetupWizardTest, DiscreteRun) {
DictionaryValue dialog_args;
// For a discrete run, we need to have ran through setup once.
diff --git a/chrome/browser/views/toolbar_view.cc b/chrome/browser/views/toolbar_view.cc
index 4c29e28..97b0381 100644
--- a/chrome/browser/views/toolbar_view.cc
+++ b/chrome/browser/views/toolbar_view.cc
@@ -20,14 +20,15 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/character_encoding.h"
#include "chrome/browser/encoding_menu_controller.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/sync/sync_status_ui_helper.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
-#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/user_data_manager.h"
#include "chrome/browser/views/bookmark_menu_button.h"
#include "chrome/browser/views/browser_actions_container.h"
@@ -1133,8 +1134,18 @@ void ToolbarView::CreateAppMenu() {
app_menu_contents_->AddSeparator();
#ifdef CHROME_PERSONALIZATION
if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableSync)) {
- app_menu_contents_->AddItem(IDC_SYNC_BOOKMARKS,
- l10n_util::GetString(IDS_SYNC_MY_BOOKMARKS_LABEL) + L"...");
+ std::wstring label;
+ std::wstring link;
+ // TODO(timsteele): Need a ui helper method to just get the type without
+ // needing labels.
+ SyncStatusUIHelper::MessageType type = SyncStatusUIHelper::GetLabels(
+ browser_->profile()->GetProfileSyncService(), &label, &link);
+ label = type == SyncStatusUIHelper::SYNCED ?
+ l10n_util::GetString(IDS_SYNC_MENU_BOOKMARKS_SYNCED_LABEL) :
+ type == SyncStatusUIHelper::SYNC_ERROR ?
+ l10n_util::GetString(IDS_SYNC_MENU_BOOKMARK_SYNC_ERROR_LABEL) :
+ l10n_util::GetString(IDS_SYNC_START_SYNC_BUTTON_LABEL);
+ app_menu_contents_->AddItem(IDC_SYNC_BOOKMARKS, label);
app_menu_contents_->AddSeparator();
}
#endif