| Index: chrome/browser/ui/webui/extensions/extension_loader_handler.cc
|
| diff --git a/chrome/browser/ui/webui/extensions/extension_loader_handler.cc b/chrome/browser/ui/webui/extensions/extension_loader_handler.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..165d6d6a5c73cb52b8cc1f6ea4a5d278933e159c
|
| --- /dev/null
|
| +++ b/chrome/browser/ui/webui/extensions/extension_loader_handler.cc
|
| @@ -0,0 +1,241 @@
|
| +// Copyright 2014 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/extensions/extension_loader_handler.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/file_util.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/strings/string16.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "base/strings/stringprintf.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "base/values.h"
|
| +#include "chrome/browser/extensions/unpacked_installer.h"
|
| +#include "chrome/browser/profiles/profile.h"
|
| +#include "chrome/browser/ui/chrome_select_file_policy.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "content/public/browser/user_metrics.h"
|
| +#include "content/public/browser/web_contents.h"
|
| +#include "content/public/browser/web_contents_view.h"
|
| +#include "content/public/browser/web_ui.h"
|
| +#include "content/public/browser/web_ui_data_source.h"
|
| +#include "extensions/browser/extension_system.h"
|
| +#include "extensions/browser/file_highlighter.h"
|
| +#include "extensions/common/constants.h"
|
| +#include "extensions/common/extension.h"
|
| +#include "extensions/common/manifest_constants.h"
|
| +#include "grit/generated_resources.h"
|
| +#include "third_party/re2/re2/re2.h"
|
| +#include "ui/base/l10n/l10n_util.h"
|
| +#include "ui/shell_dialogs/select_file_dialog.h"
|
| +
|
| +namespace extensions {
|
| +
|
| +namespace {
|
| +
|
| +// Read a file to a string and return.
|
| +std::string ReadFileToString(const base::FilePath& path) {
|
| + std::string data;
|
| + // This call can fail, but it doesn't matter for our purposes. If it fails,
|
| + // we simply return an empty string for the manifest, and ignore it.
|
| + base::ReadFileToString(path, &data);
|
| + return data;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class ExtensionLoaderHandler::FileHelper
|
| + : public ui::SelectFileDialog::Listener {
|
| + public:
|
| + explicit FileHelper(ExtensionLoaderHandler* loader_handler);
|
| + virtual ~FileHelper();
|
| +
|
| + // Create a FileDialog for the user to select the unpacked extension
|
| + // directory.
|
| + void ChooseFile();
|
| +
|
| + private:
|
| + // ui::SelectFileDialog::Listener implementation.
|
| + virtual void FileSelected(const base::FilePath& path,
|
| + int index,
|
| + void* params) OVERRIDE;
|
| + virtual void MultiFilesSelected(
|
| + const std::vector<base::FilePath>& files, void* params) OVERRIDE;
|
| +
|
| + // The associated ExtensionLoaderHandler. Weak, but guaranteed to be alive,
|
| + // as it owns this object.
|
| + ExtensionLoaderHandler* loader_handler_;
|
| +
|
| + // The dialog used to pick a directory when loading an unpacked extension.
|
| + scoped_refptr<ui::SelectFileDialog> load_extension_dialog_;
|
| +
|
| + // The last selected directory, so we can start in the same spot.
|
| + base::FilePath last_unpacked_directory_;
|
| +
|
| + // The title of the dialog.
|
| + base::string16 title_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(FileHelper);
|
| +};
|
| +
|
| +ExtensionLoaderHandler::FileHelper::FileHelper(
|
| + ExtensionLoaderHandler* loader_handler)
|
| + : loader_handler_(loader_handler),
|
| + title_(l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY)) {
|
| +}
|
| +
|
| +ExtensionLoaderHandler::FileHelper::~FileHelper() {
|
| + // There may be a pending file dialog; inform it the listener is destroyed so
|
| + // it doesn't try and call back.
|
| + if (load_extension_dialog_.get())
|
| + load_extension_dialog_->ListenerDestroyed();
|
| +}
|
| +
|
| +void ExtensionLoaderHandler::FileHelper::ChooseFile() {
|
| + static const int kFileTypeIndex = 0; // No file type information to index.
|
| + static const ui::SelectFileDialog::Type kSelectType =
|
| + ui::SelectFileDialog::SELECT_FOLDER;
|
| +
|
| + if (!load_extension_dialog_.get()) {
|
| + load_extension_dialog_ = ui::SelectFileDialog::Create(
|
| + this,
|
| + new ChromeSelectFilePolicy(
|
| + loader_handler_->web_ui()->GetWebContents()));
|
| + }
|
| +
|
| + load_extension_dialog_->SelectFile(
|
| + kSelectType,
|
| + title_,
|
| + last_unpacked_directory_,
|
| + NULL,
|
| + kFileTypeIndex,
|
| + base::FilePath::StringType(),
|
| + loader_handler_->web_ui()->
|
| + GetWebContents()->GetView()->GetTopLevelNativeWindow(),
|
| + NULL);
|
| +
|
| + content::RecordComputedAction("Options_LoadUnpackedExtension");
|
| +}
|
| +
|
| +void ExtensionLoaderHandler::FileHelper::FileSelected(
|
| + const base::FilePath& path, int index, void* params) {
|
| + loader_handler_->LoadUnpackedExtensionImpl(path);
|
| +}
|
| +
|
| +void ExtensionLoaderHandler::FileHelper::MultiFilesSelected(
|
| + const std::vector<base::FilePath>& files, void* params) {
|
| + NOTREACHED();
|
| +}
|
| +
|
| +ExtensionLoaderHandler::ExtensionLoaderHandler(Profile* profile)
|
| + : profile_(profile),
|
| + file_helper_(new FileHelper(this)),
|
| + weak_ptr_factory_(this) {
|
| + DCHECK(profile_);
|
| +}
|
| +
|
| +ExtensionLoaderHandler::~ExtensionLoaderHandler() {
|
| +}
|
| +
|
| +void ExtensionLoaderHandler::GetLocalizedValues(
|
| + content::WebUIDataSource* source) {
|
| + source->AddString(
|
| + "extensionLoadErrorHeading",
|
| + l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_HEADING));
|
| + source->AddString(
|
| + "extensionLoadErrorMessage",
|
| + l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_MESSAGE));
|
| + source->AddString(
|
| + "extensionLoadErrorRetry",
|
| + l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_RETRY));
|
| + source->AddString(
|
| + "extensionLoadErrorGiveUp",
|
| + l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_GIVE_UP));
|
| + source->AddString(
|
| + "extensionLoadCouldNotLoadManifest",
|
| + l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_COULD_NOT_LOAD_MANIFEST));
|
| +}
|
| +
|
| +void ExtensionLoaderHandler::RegisterMessages() {
|
| + web_ui()->RegisterMessageCallback(
|
| + "extensionLoaderLoadUnpacked",
|
| + base::Bind(&ExtensionLoaderHandler::HandleLoadUnpacked,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + web_ui()->RegisterMessageCallback(
|
| + "extensionLoaderRetry",
|
| + base::Bind(&ExtensionLoaderHandler::HandleRetry,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| +void ExtensionLoaderHandler::HandleLoadUnpacked(const base::ListValue* args) {
|
| + DCHECK(args->empty());
|
| + file_helper_->ChooseFile();
|
| +}
|
| +
|
| +void ExtensionLoaderHandler::HandleRetry(const base::ListValue* args) {
|
| + DCHECK(args->empty());
|
| + LoadUnpackedExtensionImpl(failed_path_);
|
| +}
|
| +
|
| +void ExtensionLoaderHandler::LoadUnpackedExtensionImpl(
|
| + const base::FilePath& file_path) {
|
| + scoped_refptr<UnpackedInstaller> installer = UnpackedInstaller::Create(
|
| + ExtensionSystem::Get(profile_)->extension_service());
|
| + installer->set_on_failure_callback(
|
| + base::Bind(&ExtensionLoaderHandler::OnLoadFailure,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| + installer->Load(file_path);
|
| +}
|
| +
|
| +void ExtensionLoaderHandler::OnLoadFailure(const base::FilePath& file_path,
|
| + const std::string& error) {
|
| + failed_path_ = file_path;
|
| + size_t line = 0u;
|
| + size_t column = 0u;
|
| + std::string regex =
|
| + base::StringPrintf("%s Line: (\\d+), column: (\\d+), Syntax error.",
|
| + manifest_errors::kManifestParseError);
|
| + // If this was a manifest error, then we can get the manifest and
|
| + // highlight the error. This will read the manifest to disk, and call
|
| + // NotifyFrontendOfFailure with the read manifest contents.
|
| + if (re2::RE2::FullMatch(error, regex, &line, &column)) {
|
| + base::PostTaskAndReplyWithResult(
|
| + content::BrowserThread::GetBlockingPool(),
|
| + FROM_HERE,
|
| + base::Bind(&ReadFileToString, file_path.Append(kManifestFilename)),
|
| + base::Bind(&ExtensionLoaderHandler::NotifyFrontendOfFailure,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + file_path,
|
| + error,
|
| + line));
|
| + return;
|
| + }
|
| +
|
| + // Otherwise, just show the error.
|
| + NotifyFrontendOfFailure(file_path, error, 0u, base::EmptyString());
|
| +}
|
| +
|
| +void ExtensionLoaderHandler::NotifyFrontendOfFailure(
|
| + const base::FilePath& file_path,
|
| + const std::string& error,
|
| + size_t line_number,
|
| + const std::string& manifest) {
|
| + base::DictionaryValue manifest_value;
|
| + if (!manifest.empty()) {
|
| + SourceHighlighter highlighter(manifest, line_number);
|
| + highlighter.SetHighlightedRegions(&manifest_value);
|
| + }
|
| +
|
| + base::StringValue file_value(file_path.LossyDisplayName());
|
| + base::StringValue error_value(base::UTF8ToUTF16(error));
|
| + web_ui()->CallJavascriptFunction(
|
| + "extensions.ExtensionLoader.notifyLoadFailed",
|
| + file_value,
|
| + error_value,
|
| + manifest_value);
|
| +}
|
| +
|
| +} // namespace extensions
|
|
|