| // Copyright (c) 2012 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/webui/sync_internals_ui.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/logging.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/tracked_objects.h" |
| #include "base/values.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/sync/about_sync_util.h" |
| #include "chrome/browser/sync/profile_sync_service.h" |
| #include "chrome/browser/sync/profile_sync_service_factory.h" |
| #include "chrome/browser/sync/sync_ui_util.h" |
| #include "chrome/common/extensions/extension_messages.h" |
| #include "chrome/common/url_constants.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_ui.h" |
| #include "content/public/browser/web_ui_data_source.h" |
| #include "grit/sync_internals_resources.h" |
| #include "sync/internal_api/public/util/weak_handle.h" |
| #include "sync/js/js_arg_list.h" |
| #include "sync/js/js_controller.h" |
| #include "sync/js/js_event_details.h" |
| #include "ui/base/resource/resource_bundle.h" |
| |
| using syncer::JsArgList; |
| using syncer::JsEventDetails; |
| using syncer::JsReplyHandler; |
| using syncer::WeakHandle; |
| using content::WebContents; |
| |
| namespace { |
| |
| content::WebUIDataSource* CreateSyncInternalsHTMLSource() { |
| content::WebUIDataSource* source = |
| content::WebUIDataSource::Create(chrome::kChromeUISyncInternalsHost); |
| |
| source->SetJsonPath("strings.js"); |
| source->AddResourcePath("sync_index.js", IDR_SYNC_INTERNALS_INDEX_JS); |
| source->AddResourcePath("chrome_sync.js", |
| IDR_SYNC_INTERNALS_CHROME_SYNC_JS); |
| source->AddResourcePath("sync_log.js", IDR_SYNC_INTERNALS_SYNC_LOG_JS); |
| source->AddResourcePath("sync_node_browser.js", |
| IDR_SYNC_INTERNALS_SYNC_NODE_BROWSER_JS); |
| source->AddResourcePath("sync_search.js", |
| IDR_SYNC_INTERNALS_SYNC_SEARCH_JS); |
| source->AddResourcePath("about.js", IDR_SYNC_INTERNALS_ABOUT_JS); |
| source->AddResourcePath("data.js", IDR_SYNC_INTERNALS_DATA_JS); |
| source->AddResourcePath("events.js", IDR_SYNC_INTERNALS_EVENTS_JS); |
| source->AddResourcePath("notifications.js", |
| IDR_SYNC_INTERNALS_NOTIFICATIONS_JS); |
| source->AddResourcePath("search.js", IDR_SYNC_INTERNALS_SEARCH_JS); |
| source->AddResourcePath("node_browser.js", |
| IDR_SYNC_INTERNALS_NODE_BROWSER_JS); |
| source->AddResourcePath("traffic.js", IDR_SYNC_INTERNALS_TRAFFIC_JS); |
| source->SetDefaultResource(IDR_SYNC_INTERNALS_INDEX_HTML); |
| return source; |
| } |
| |
| } // namespace |
| |
| namespace { |
| |
| // Gets the ProfileSyncService of the underlying original profile. |
| // May return NULL (e.g., if sync is disabled on the command line). |
| ProfileSyncService* GetProfileSyncService(Profile* profile) { |
| return ProfileSyncServiceFactory::GetInstance()->GetForProfile( |
| profile->GetOriginalProfile()); |
| } |
| |
| } // namespace |
| |
| SyncInternalsUI::SyncInternalsUI(content::WebUI* web_ui) |
| : WebUIController(web_ui), |
| weak_ptr_factory_(this) { |
| // TODO(akalin): Fix. |
| Profile* profile = Profile::FromWebUI(web_ui); |
| content::WebUIDataSource::Add(profile, CreateSyncInternalsHTMLSource()); |
| ProfileSyncService* sync_service = GetProfileSyncService(profile); |
| if (sync_service) { |
| js_controller_ = sync_service->GetJsController(); |
| } |
| if (js_controller_.get()) { |
| js_controller_->AddJsEventHandler(this); |
| } |
| } |
| |
| SyncInternalsUI::~SyncInternalsUI() { |
| if (js_controller_.get()) { |
| js_controller_->RemoveJsEventHandler(this); |
| } |
| } |
| |
| bool SyncInternalsUI::OverrideHandleWebUIMessage(const GURL& source_url, |
| const std::string& name, |
| const ListValue& content) { |
| scoped_ptr<ListValue> content_copy(content.DeepCopy()); |
| JsArgList args(content_copy.get()); |
| VLOG(1) << "Received message: " << name << " with args " |
| << args.ToString(); |
| if (name == "testResult") { |
| // Let the test framework handle test results. |
| // TODO(zea): fix this. crbug.com/316378 |
| return false; |
| } else if (name == "getAboutInfo") { |
| // We handle this case directly because it needs to work even if |
| // the sync service doesn't exist. |
| ListValue return_args; |
| Profile* profile = Profile::FromWebUI(web_ui()); |
| ProfileSyncService* service = GetProfileSyncService(profile); |
| return_args.Append( |
| sync_ui_util::ConstructAboutInformation(service).release()); |
| HandleJsReply(name, JsArgList(&return_args)); |
| } else { |
| if (js_controller_.get()) { |
| js_controller_->ProcessJsMessage( |
| name, args, |
| MakeWeakHandle(weak_ptr_factory_.GetWeakPtr())); |
| } else { |
| LOG(WARNING) << "No sync service; dropping message " << name |
| << " with args " << args.ToString(); |
| } |
| } |
| return true; |
| } |
| |
| void SyncInternalsUI::HandleJsEvent( |
| const std::string& name, const JsEventDetails& details) { |
| VLOG(1) << "Handling event: " << name << " with details " |
| << details.ToString(); |
| const std::string& event_handler = "chrome.sync." + name + ".fire"; |
| std::vector<const Value*> arg_list(1, &details.Get()); |
| web_ui()->CallJavascriptFunction(event_handler, arg_list); |
| } |
| |
| void SyncInternalsUI::HandleJsReply( |
| const std::string& name, const JsArgList& args) { |
| VLOG(1) << "Handling reply for " << name << " message with args " |
| << args.ToString(); |
| const std::string& reply_handler = "chrome.sync." + name + ".handleReply"; |
| std::vector<const Value*> arg_list(args.Get().begin(), args.Get().end()); |
| web_ui()->CallJavascriptFunction(reply_handler, arg_list); |
| } |