diff options
author | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-08 01:18:02 +0000 |
---|---|---|
committer | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-08 01:18:02 +0000 |
commit | 13555c122fbc9ec2a6c1a4cbace288ec7892be6e (patch) | |
tree | b78bb0337bf633e7ecff2adc004c4a93542bdba9 /chrome/browser | |
parent | 2c8311e9badbe99ba50d6429a2c13bb8be89ff80 (diff) | |
download | chromium_src-13555c122fbc9ec2a6c1a4cbace288ec7892be6e.zip chromium_src-13555c122fbc9ec2a6c1a4cbace288ec7892be6e.tar.gz chromium_src-13555c122fbc9ec2a6c1a4cbace288ec7892be6e.tar.bz2 |
Reland: HTML Pack Extension Dialog / Linux & Mac Packaging Support.
original issue: http://codereview.chromium.org/207062
The issue had to do with a symbol collison with the nss libraries (which are currently out-of-date) on the build bots.
HTML Pack Extension Dialog. This removes the views implementation of the ExtensionPackDialog, and implements the dialog in html in the extensions_ui DOMUI.
Additionally, support is added for packaging extensions via ---pack-extension on linux and mac
BUG=20668, 20669
TBR=aa,wtc
Review URL: http://codereview.chromium.org/265032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28365 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser_init.cc | 27 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service_unittest.cc | 2 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_ui.cc | 138 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_ui.h | 23 | ||||
-rw-r--r-- | chrome/browser/extensions/pack_extension_job.h | 8 | ||||
-rw-r--r-- | chrome/browser/net/chrome_url_request_context.cc | 3 | ||||
-rw-r--r-- | chrome/browser/resources/extensions_ui.html | 188 | ||||
-rw-r--r-- | chrome/browser/views/extensions/extension_pack_dialog.cc | 233 |
8 files changed, 355 insertions, 267 deletions
diff --git a/chrome/browser/browser_init.cc b/chrome/browser/browser_init.cc index b551bcf..ce0c7f4 100644 --- a/chrome/browser/browser_init.cc +++ b/chrome/browser/browser_init.cc @@ -28,9 +28,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_window.h" #include "chrome/browser/defaults.h" -#if defined(OS_WIN) // TODO(port) #include "chrome/browser/extensions/extension_creator.h" -#endif #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/extensions/user_script_master.h" #include "chrome/browser/first_run.h" @@ -367,6 +365,20 @@ GURL GetWelcomePageURL() { return GURL(welcome_url); } +void ShowPackExtensionMessage(const std::wstring caption, + const std::wstring message) { +#if defined(OS_WIN) + win_util::MessageBox(NULL, message, caption, MB_OK | MB_SETFOREGROUND); +#else + // Just send caption & text to stdout on mac & linux. + std::string out_text = WideToASCII(caption); + out_text.append("\n\n"); + out_text.append(WideToASCII(message)); + out_text.append("\n"); + printf(out_text.c_str()); +#endif +} + } // namespace // static @@ -751,7 +763,6 @@ bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line, // ExtensionCreator depends on base/crypto/rsa_private_key and // base/crypto/signature_creator, both of which only have windows // implementations. -#if defined(OS_WIN) scoped_ptr<ExtensionCreator> creator(new ExtensionCreator()); if (creator->Run(src_dir, crx_path, private_key_path, output_private_key_path)) { @@ -769,16 +780,12 @@ bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line, message = StringPrintf(L"Created the extension:\n\n%ls", crx_path.ToWStringHack().c_str()); } - win_util::MessageBox(NULL, message, L"Extension Packaging Success", - MB_OK | MB_SETFOREGROUND); + ShowPackExtensionMessage(L"Extension Packaging Success", message); } else { - win_util::MessageBox(NULL, UTF8ToWide(creator->error_message()), - L"Extension Packaging Error", MB_OK | MB_SETFOREGROUND); + ShowPackExtensionMessage(L"Extension Packaging Error", + UTF8ToWide(creator->error_message())); return false; } -#else - NOTIMPLEMENTED() << " extension creation not implemented on POSIX."; -#endif // defined(OS_WIN) return false; } } diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc index 578bde2..d5d629f 100644 --- a/chrome/browser/extensions/extensions_service_unittest.cc +++ b/chrome/browser/extensions/extensions_service_unittest.cc @@ -721,7 +721,6 @@ TEST_F(ExtensionsServiceTest, InstallExtension) { // TODO(erikkay): add tests for upgrade cases. } -#if defined(OS_WIN) // TODO(port) // Test Packaging and installing an extension. // TODO(rafaelw): add more tests for failure cases. TEST_F(ExtensionsServiceTest, PackExtension) { @@ -785,7 +784,6 @@ TEST_F(ExtensionsServiceTest, PackExtensionOpenSSLKey) { file_util::Delete(crx_path, false); } -#endif // defined(OS_WIN) TEST_F(ExtensionsServiceTest, InstallTheme) { InitializeEmptyExtensionsService(); diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc index 7313f50..ff2505f 100644 --- a/chrome/browser/extensions/extensions_ui.cc +++ b/chrome/browser/extensions/extensions_ui.cc @@ -9,6 +9,7 @@ #include "base/string_util.h" #include "base/thread.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/chrome_thread.h" #include "chrome/browser/debugger/devtools_manager.h" #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/extensions/extensions_service.h" @@ -47,6 +48,14 @@ void ExtensionsUIHTMLSource::StartDataRequest(const std::string& path, DictionaryValue localized_strings; localized_strings.SetString(L"title", l10n_util::GetString(IDS_EXTENSIONS_TITLE)); + localized_strings.SetString(L"packDialogHeading", + l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_HEADING)); + localized_strings.SetString(L"rootDirectoryLabel", + l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL)); + localized_strings.SetString(L"packDialogBrowse", + l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_BROWSE)); + localized_strings.SetString(L"privateKeyLabel", + l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL)); static const base::StringPiece extensions_html( ResourceBundle::GetSharedInstance().GetRawDataResource( @@ -91,6 +100,8 @@ void ExtensionsDOMHandler::RegisterMessages() { NewCallback(this, &ExtensionsDOMHandler::HandlePackMessage)); dom_ui_->RegisterMessageCallback("autoupdate", NewCallback(this, &ExtensionsDOMHandler::HandleAutoUpdateMessage)); + dom_ui_->RegisterMessageCallback("selectFilePath", + NewCallback(this, &ExtensionsDOMHandler::HandleSelectFilePathMessage)); } void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) { @@ -187,18 +198,77 @@ void ExtensionsDOMHandler::HandleUninstallMessage(const Value* value) { } void ExtensionsDOMHandler::HandleLoadMessage(const Value* value) { - load_extension_dialog_ = SelectFileDialog::Create(this); - load_extension_dialog_->SelectFile( - SelectFileDialog::SELECT_FOLDER, - l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY), - FilePath(), NULL, 0, FILE_PATH_LITERAL(""), - dom_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL); + std::string string_path; + CHECK(value->IsType(Value::TYPE_LIST)); + const ListValue* list = static_cast<const ListValue*>(value); + CHECK(list->GetSize() == 1) << list->GetSize(); + CHECK(list->GetString(0, &string_path)); + FilePath file_path = FilePath::FromWStringHack(ASCIIToWide(string_path)); + extensions_service_->LoadExtension(file_path); +} + +void ExtensionsDOMHandler::ShowAlert(const std::string& message) { + ListValue arguments; + arguments.Append(Value::CreateStringValue(message)); + dom_ui_->CallJavascriptFunction(L"alert", arguments); } void ExtensionsDOMHandler::HandlePackMessage(const Value* value) { -#if defined(OS_WIN) - ShowPackDialog(); -#endif + std::string extension_path; + std::string private_key_path; + CHECK(value->IsType(Value::TYPE_LIST)); + const ListValue* list = static_cast<const ListValue*>(value); + CHECK(list->GetSize() == 2); + CHECK(list->GetString(0, &extension_path)); + CHECK(list->GetString(1, &private_key_path)); + + FilePath root_directory = FilePath::FromWStringHack(ASCIIToWide( + extension_path)); + FilePath key_file = FilePath::FromWStringHack(ASCIIToWide(private_key_path)); + + if (root_directory.empty()) { + if (extension_path.empty()) { + ShowAlert(l10n_util::GetStringUTF8( + IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED)); + } else { + ShowAlert(l10n_util::GetStringUTF8( + IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID)); + } + + return; + } + + if (!private_key_path.empty() && key_file.empty()) { + ShowAlert(l10n_util::GetStringUTF8( + IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID)); + return; + } + + pack_job_ = new PackExtensionJob(this, root_directory, key_file, + ChromeThread::GetMessageLoop(ChromeThread::FILE)); +} + +void ExtensionsDOMHandler::OnPackSuccess(const FilePath& crx_file, + const FilePath& pem_file) { + std::string message; + if (!pem_file.empty()) { + message = WideToASCII(l10n_util::GetStringF( + IDS_EXTENSION_PACK_DIALOG_SUCCESS_BODY_NEW, + crx_file.ToWStringHack(), + pem_file.ToWStringHack())); + } else { + message = WideToASCII(l10n_util::GetStringF( + IDS_EXTENSION_PACK_DIALOG_SUCCESS_BODY_UPDATE, + crx_file.ToWStringHack())); + } + ShowAlert(message); + + ListValue results; + dom_ui_->CallJavascriptFunction(L"hidePackDialog", results); +} + +void ExtensionsDOMHandler::OnPackFailure(const std::wstring& error) { + ShowAlert(WideToASCII(error)); } void ExtensionsDOMHandler::HandleAutoUpdateMessage(const Value* value) { @@ -208,9 +278,55 @@ void ExtensionsDOMHandler::HandleAutoUpdateMessage(const Value* value) { } } +void ExtensionsDOMHandler::HandleSelectFilePathMessage(const Value* value) { + std::string select_type; + std::string operation; + CHECK(value->IsType(Value::TYPE_LIST)); + const ListValue* list = static_cast<const ListValue*>(value); + CHECK(list->GetSize() == 2); + CHECK(list->GetString(0, &select_type)); + CHECK(list->GetString(1, &operation)); + + SelectFileDialog::Type type = SelectFileDialog::SELECT_FOLDER; + static SelectFileDialog::FileTypeInfo info; + int file_type_index = 0; + if (select_type == "file") + type = SelectFileDialog::SELECT_OPEN_FILE; + + string16 select_title; + if (operation == "load") + select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); + else if (operation == "packRoot") + select_title = l10n_util::GetStringUTF16( + IDS_EXTENSION_PACK_DIALOG_SELECT_ROOT); + else if (operation == "pem") { + select_title = l10n_util::GetStringUTF16( + IDS_EXTENSION_PACK_DIALOG_SELECT_KEY); + info.extensions.push_back(std::vector<FilePath::StringType>()); + info.extensions.front().push_back(FILE_PATH_LITERAL("pem")); + info.extension_description_overrides.push_back(WideToUTF16( + l10n_util::GetString( + IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION))); + info.include_all_files = true; + file_type_index = 1; + } else { + NOTREACHED(); + return; + } + + load_extension_dialog_ = SelectFileDialog::Create(this); + load_extension_dialog_->SelectFile(type, select_title, FilePath(), &info, + file_type_index, FILE_PATH_LITERAL(""), + dom_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL); +} + + void ExtensionsDOMHandler::FileSelected(const FilePath& path, int index, void* params) { - extensions_service_->LoadExtension(path); + // Add the extensions to the results structure. + ListValue results; + results.Append(Value::CreateStringValue(path.value())); + dom_ui_->CallJavascriptFunction(L"window.handleFilePathSelected", results); } void ExtensionsDOMHandler::Observe(NotificationType type, @@ -339,6 +455,8 @@ std::vector<ExtensionPage> ExtensionsDOMHandler::GetActivePagesForExtension( } ExtensionsDOMHandler::~ExtensionsDOMHandler() { + if (pack_job_.get()) + pack_job_->ClearClient(); } // ExtensionsDOMHandler, public: ----------------------------------------------- diff --git a/chrome/browser/extensions/extensions_ui.h b/chrome/browser/extensions/extensions_ui.h index 80ddf4d..908c9f3 100644 --- a/chrome/browser/extensions/extensions_ui.h +++ b/chrome/browser/extensions/extensions_ui.h @@ -10,6 +10,7 @@ #include "chrome/browser/dom_ui/chrome_url_data_manager.h" #include "chrome/browser/dom_ui/dom_ui.h" +#include "chrome/browser/extensions/pack_extension_job.h" #include "chrome/browser/shell_dialogs.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" @@ -52,6 +53,7 @@ class ExtensionsUIHTMLSource : public ChromeURLDataManager::DataSource { class ExtensionsDOMHandler : public DOMMessageHandler, public NotificationObserver, + public PackExtensionJob::Client, public SelectFileDialog::Listener { public: explicit ExtensionsDOMHandler(ExtensionsService* extension_service); @@ -71,13 +73,13 @@ class ExtensionsDOMHandler const UserScript& script, const FilePath& extension_path); - private: -#if defined(OS_WIN) - // The implementation of this method is platform-specific and defined - // elsewhere. - static void ShowPackDialog(); -#endif + // ExtensionPackJob::Client + virtual void OnPackSuccess(const FilePath& crx_file, + const FilePath& key_file); + + virtual void OnPackFailure(const std::wstring& message); + private: // Callback for "requestExtensionsData" message. void HandleRequestExtensionsData(const Value* value); @@ -102,6 +104,12 @@ class ExtensionsDOMHandler // Callback for "autoupdate" message. void HandleAutoUpdateMessage(const Value* value); + // Utility for calling javascript window.alert in the page. + void ShowAlert(const std::string& message); + + // Callback for "selectFilePath" message. + void HandleSelectFilePathMessage(const Value* value); + // SelectFileDialog::Listener virtual void FileSelected(const FilePath& path, int index, void* params); @@ -126,6 +134,9 @@ class ExtensionsDOMHandler // Used to pick the directory when loading an extension. scoped_refptr<SelectFileDialog> load_extension_dialog_; + // Used to package the extension. + scoped_refptr<PackExtensionJob> pack_job_; + // We monitor changes to the extension system so that we can reload when // necessary. NotificationRegistrar registrar_; diff --git a/chrome/browser/extensions/pack_extension_job.h b/chrome/browser/extensions/pack_extension_job.h index ec00f21..8c3cf26 100644 --- a/chrome/browser/extensions/pack_extension_job.h +++ b/chrome/browser/extensions/pack_extension_job.h @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef CHROME_BROWSER_EXTENSIONS_PACK_EXTENSION_JOB_UI_H_ +#define CHROME_BROWSER_EXTENSIONS_PACK_EXTENSION_JOB_UI_H_ + #include <string> #include "base/file_path.h" @@ -11,7 +14,7 @@ class MessageLoop; // Manages packing an extension on the file thread and reporting the result // back to the UI. -class PackExtensionJob : public base::RefCounted<PackExtensionJob> { +class PackExtensionJob : public base::RefCountedThreadSafe<PackExtensionJob> { public: // Interface for people who want to use PackExtensionJob to implement. @@ -46,3 +49,6 @@ class PackExtensionJob : public base::RefCounted<PackExtensionJob> { DISALLOW_COPY_AND_ASSIGN(PackExtensionJob); }; + +#endif // CHROME_BROWSER_EXTENSIONS_PACK_EXTENSION_JOB_UI_H_ + diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc index 2c68419..2918b1f 100644 --- a/chrome/browser/net/chrome_url_request_context.cc +++ b/chrome/browser/net/chrome_url_request_context.cc @@ -520,9 +520,8 @@ void ChromeURLRequestContext::OnDefaultCharsetChange( void ChromeURLRequestContext::OnNewExtensions(const std::string& id, const FilePath& path) { - if (!is_off_the_record_) { + if (!is_off_the_record_) extension_paths_[id] = path; - } } void ChromeURLRequestContext::OnUnloadedExtension(const std::string& id) { diff --git a/chrome/browser/resources/extensions_ui.html b/chrome/browser/resources/extensions_ui.html index 0c9273b..99076f8 100644 --- a/chrome/browser/resources/extensions_ui.html +++ b/chrome/browser/resources/extensions_ui.html @@ -111,6 +111,87 @@ button { font-size:100%; } +#dialogBackground, #dialogBackground div { + display: -webkit-box; + -webkit-box-align: center; +} + +#dialog input[type="button"] { + font-size: 12px; + height: 25px; + width: 100px; +} + +#dialog input[type="text"] { + width: 220px; + font-size: 12px; + font-family: Arial, Helvetica, sans-serif; +} + +#dialogBackground { + background-color: rgba(0, 0, 0, .2); + display: none; + height: 100%; + left: 0; + position: fixed; + top: 0; + width: 100%; + z-index: 1; + -webkit-box-orient: vertical; + -webkit-user-select:none; +} + +#dialogHBackground { + height: 100%; + -webkit-box-orient: horizontal; +} + +#dialog { + background-color: #5296DE; + border: 1px solid #3A75BD; + border-radius: 6px 6px; + font-size: 12px; + width: 500px; + -webkit-box-orient: vertical; +} + +#dialogHeader { + background-color: rgba(0,0,0,0); + color: white; + margin: 4px; + width: 100%; +} + +#dialogBody { + background-color: rgb(240, 240, 240); + border: 1px solid #3A75BD; + border-bottom-left-radius: 4px 4px; + border-bottom-right-radius: 4px 4px; + margin: 0px 2px 2px 2px; + -webkit-box-orient: vertical; +} + +#dialogContentHeader { + margin: 16px; +} + +.dialogBrowseRow { + margin-left: -24px; + width: 100%; + -webkit-box-orient: horizontal; + -webkit-box-pack: end; +} + +.dialogBrowseRow>* { + margin: 2px +} + +#dialogContentFooter { + margin-bottom: 6px; + margin-left: -12px; + margin-top: 20px; +} + </style> <script> /** @@ -264,17 +345,69 @@ function handleUninstallExtension(node) { } /** + * Utility function which asks the C++ to show a platform-specific file select + * dialog, and fire |callback| with the |filePath| that resulted. |selectType| + * can be either 'file' or 'folder'. |operation| can be 'load', 'packRoot', + * or 'pem' which are signals to the C++ to do some operation-specific + * configuration. + */ +function showFileDialog(selectType, operation, callback) { + handleFilePathSelected = function(filePath) { + callback(filePath); + handleFilePathSelected = function() {}; + }; + + chrome.send('selectFilePath', [selectType, operation]); +} + +/** * Handles the "Load extension..." button being pressed. */ function loadExtension() { - chrome.send('load', []); + showFileDialog('folder', 'load', function(filePath) { + chrome.send('load', [String(filePath)]); + }); } /** * Handles the "Pack extension..." button being pressed. */ function packExtension() { - chrome.send('pack', []); + var extensionPath = document.getElementById('extensionPathText').value; + var privateKeyPath = document.getElementById('privateKeyPath').value; + chrome.send('pack', [extensionPath, privateKeyPath]); +} + +/** + * Shows to modal HTML pack dialog. + */ +function showPackDialog() { + document.getElementById('dialogBackground').style.display="-webkit-box"; +} + +/** + * Hides the pack dialog. + */ +function hidePackDialog() { + document.getElementById('dialogBackground').style.display="none" +} + +/** + * Pop up a select dialog to capture the extension path. + */ +function selectExtensionPath() { + showFileDialog('folder', 'packRoot', function(filePath) { + document.getElementById('extensionPathText').value = filePath; + }); +} + +/** + * Pop up a select dialog to capture the private key path. + */ +function selectPrivateKeyPath() { + showFileDialog('file', 'pem', function(filePath) { + document.getElementById('privateKeyPath').value = filePath; + }); } /** @@ -287,6 +420,55 @@ function autoUpdate() { </script> </head> <body onload="requestExtensionsData();"> + <div id="dialogBackground"> + <div id="dialogHBackground"> + <div id="dialog"> + <div id="dialogHeader"> + Pack Extension + </div> + <div id="dialogBody"> + <div id="dialogContentHeader" i18n-content="packDialogHeading"> + HEADING + </div> + <div class="dialogBrowseRow"> + <div i18n-content="rootDirectoryLabel"> + ROOT_DIR + </div> + <div> + <input type="text" id="extensionPathText"> + </div> + <div> + <input type="button" value="BROWSE" + i18n-values="value:packDialogBrowse" + onclick="selectExtensionPath();"> + </div> + </div> + <div class="dialogBrowseRow"> + <div i18n-content="privateKeyLabel"> + PRIVATE_KEY + </div> + <div> + <input type="text" id="privateKeyPath"> + </div> + <div> + <input type="button" value="BROWSE" + i18n-values="value:packDialogBrowse" + onclick="selectPrivateKeyPath();"> + </div> + </div> + <div class="dialogBrowseRow" id="dialogContentFooter"> + <div> + <input type="button" value="OK" onclick="packExtension();"> + </div> + <div> + <input type="button" value="Cancel" onclick="hidePackDialog();"> + </div> + </div> + </div> + </div> + </div> + </div> + <div id="body-container" style="display:none;"> <div id="header"><h1>About extensions</h1></div> @@ -356,7 +538,7 @@ function autoUpdate() { <div class="sidebar-content"> <button onclick="loadExtension()">Load unpacked extension...</button><br /> - <button onclick="packExtension()">Pack extension...</button><br /> + <button onclick="showPackDialog()">Pack extension...</button><br /> <button onclick="autoUpdate()">Update extensions now</button> </div> </td> diff --git a/chrome/browser/views/extensions/extension_pack_dialog.cc b/chrome/browser/views/extensions/extension_pack_dialog.cc deleted file mode 100644 index 3b66cc7..0000000 --- a/chrome/browser/views/extensions/extension_pack_dialog.cc +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright (c) 2009 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 "app/gfx/font.h" -#include "app/l10n_util.h" -#include "app/win_util.h" -#include "chrome/browser/browser_list.h" -#include "chrome/browser/browser_window.h" -#include "chrome/browser/chrome_thread.h" -#include "chrome/browser/extensions/extensions_ui.h" -#include "chrome/browser/extensions/pack_extension_job.h" -#include "chrome/browser/shell_dialogs.h" -#include "grit/generated_resources.h" -#include "views/controls/label.h" -#include "views/controls/button/native_button.h" -#include "views/controls/textfield/textfield.h" -#include "views/standard_layout.h" -#include "views/view.h" -#include "views/window/dialog_client_view.h" -#include "views/window/dialog_delegate.h" -#include "views/window/window.h" - -namespace { - -// Puts up the the pack dialog, which has this basic layout: -// -// Select the extension to pack. -// -// Extension root: [ ] [browse] -// Extension key file: [ ] [browse] -// -// [ok] [cancel] -class PackDialogContent - : public views::View, - public PackExtensionJob::Client, - public SelectFileDialog::Listener, - public views::ButtonListener, - public views::DialogDelegate { - public: - PackDialogContent() : ok_button_(NULL) { - using views::GridLayout; - - // Setup the layout. - views::GridLayout* layout = CreatePanelGridLayout(this); - SetLayoutManager(layout); - - views::ColumnSet* columns = layout->AddColumnSet(0); - columns->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1, - GridLayout::USE_PREF, 0, 0); - columns->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); - columns->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 1, - GridLayout::USE_PREF, 0, 0); - columns->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); - columns->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1, - GridLayout::USE_PREF, 0, 0); - - layout->StartRow(0, 0); - views::Label* heading = new views::Label( - l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_HEADING)); - heading->SetMultiLine(true); - heading->SetHorizontalAlignment(views::Label::ALIGN_LEFT); - layout->AddView(heading, 5, 1, GridLayout::FILL, GridLayout::LEADING); - - layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing); - - layout->StartRow(0, 0); - layout->AddView(new views::Label(l10n_util::GetString( - IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL))); - extension_root_textbox_ = new views::Textfield(); - extension_root_textbox_->set_default_width_in_chars(32); - layout->AddView(extension_root_textbox_); - extension_root_button_ = new views::NativeButton(this, l10n_util::GetString( - IDS_EXTENSION_PACK_DIALOG_BROWSE)); - layout->AddView(extension_root_button_); - - layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); - - layout->StartRow(0, 0); - layout->AddView(new views::Label(l10n_util::GetString( - IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL))); - private_key_textbox_ = new views::Textfield(); - private_key_textbox_->set_default_width_in_chars(32); - layout->AddView(private_key_textbox_); - private_key_button_ = new views::NativeButton(this, l10n_util::GetString( - IDS_EXTENSION_PACK_DIALOG_BROWSE)); - layout->AddView(private_key_button_); - } - - // PackExtensionJob::Client - virtual void OnPackSuccess(const FilePath& crx_file, - const FilePath& pem_file) { - ok_button_->SetEnabled(true); - std::wstring message; - if (!pem_file.empty()) { - message = l10n_util::GetStringF( - IDS_EXTENSION_PACK_DIALOG_SUCCESS_BODY_NEW, - crx_file.ToWStringHack(), - pem_file.ToWStringHack()); - } else { - message = l10n_util::GetStringF( - IDS_EXTENSION_PACK_DIALOG_SUCCESS_BODY_UPDATE, - crx_file.ToWStringHack()); - } - win_util::MessageBox(GetWindow()->GetNativeWindow(), message, - l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_SUCCESS_TITLE), - MB_OK | MB_SETFOREGROUND); - GetWindow()->Close(); - } - - void OnPackFailure(const std::wstring& error) { - ok_button_->SetEnabled(true); - win_util::MessageBox(GetWindow()->GetNativeWindow(), error, - l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_FAILURE_TITLE), - MB_OK | MB_SETFOREGROUND); - } - - private: - // DialogDelegate - virtual bool Accept() { - FilePath root_directory = FilePath::FromWStringHack( - extension_root_textbox_->text()); - FilePath key_file = FilePath::FromWStringHack(private_key_textbox_->text()); - - if (root_directory.empty()) { - if (extension_root_textbox_->text().empty()) { - OnPackFailure(l10n_util::GetString( - IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED)); - } else { - OnPackFailure(l10n_util::GetString( - IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID)); - } - - return false; - } - - if (!private_key_textbox_->text().empty() && key_file.empty()) { - OnPackFailure(l10n_util::GetString( - IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID)); - return false; - } - - pack_job_ = new PackExtensionJob(this, root_directory, key_file, - ChromeThread::GetMessageLoop(ChromeThread::FILE)); - - // Prevent the dialog from closing because PackExtensionJob is asynchronous. - // We need to wait to find out if it succeeded before closing the window. - // - // Also disable the OK button while this is going so the user understands - // that something is happening. - views::DialogClientView* dialog = static_cast<views::DialogClientView*>( - GetWindow()->GetClientView()); - ok_button_ = dialog->ok_button(); - ok_button_->SetEnabled(false); - return false; - } - - virtual void OnClose() { - if (pack_job_) - pack_job_->ClearClient(); - } - - // WindowDelegate - virtual std::wstring GetWindowTitle() const { - return l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_TITLE); - } - virtual views::View* GetContentsView() { - return this; - } - - // ButtonListener - virtual void ButtonPressed(views::Button* sender, const views::Event& event) { - file_dialog_ = SelectFileDialog::Create(this); - - if (sender == extension_root_button_) { - file_dialog_->SelectFile(SelectFileDialog::SELECT_FOLDER, - l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_SELECT_ROOT), - FilePath::FromWStringHack(extension_root_textbox_->text()), - NULL, 0, FILE_PATH_LITERAL(""), - GetWindow()->GetNativeWindow(), - extension_root_textbox_); - } else { - static SelectFileDialog::FileTypeInfo info; - info.extensions.push_back(std::vector<FilePath::StringType>()); - info.extensions.front().push_back(FILE_PATH_LITERAL("pem")); - info.extension_description_overrides.push_back(l10n_util::GetString( - IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION)); - info.include_all_files = true; - - file_dialog_->SelectFile(SelectFileDialog::SELECT_OPEN_FILE, - l10n_util::GetString(IDS_EXTENSION_PACK_DIALOG_SELECT_KEY), - FilePath::FromWStringHack(private_key_textbox_->text()), - &info, 1, FILE_PATH_LITERAL(""), - GetWindow()->GetNativeWindow(), - private_key_textbox_); - } - } - - // SelectFileDialog::Listener - virtual void MultiFilesSelected( - const std::vector<FilePath>& files, void* params) {}; - virtual void FileSelectionCanceled(void* params) {}; - virtual void FileSelected(const FilePath& path, int index, void* params) { - static_cast<views::Textfield*>(params)->SetText(path.ToWStringHack()); - } - - views::Textfield* extension_root_textbox_; - views::Textfield* private_key_textbox_; - views::NativeButton* extension_root_button_; - views::NativeButton* private_key_button_; - views::NativeButton* ok_button_; - - scoped_refptr<SelectFileDialog> file_dialog_; - scoped_refptr<PackExtensionJob> pack_job_; - - DISALLOW_COPY_AND_ASSIGN(PackDialogContent); -}; - -} // namespace - -// static -void ExtensionsDOMHandler::ShowPackDialog() { - Browser* browser = BrowserList::GetLastActive(); - if (!browser) - return; - - BrowserWindow* window = browser->window(); - if (!window) - return; - - views::Window::CreateChromeWindow(window->GetNativeHandle(), - gfx::Rect(400, 0), new PackDialogContent())->Show(); -} |