blob: 0018e8bc2d612daadf365a7ccd832f16e093d087 [file] [log] [blame] [edit]
// 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/debugger/devtools_file_helper.h"
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/file_util.h"
#include "base/lazy_instance.h"
#include "base/md5.h"
#include "base/value_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/chrome_select_file_policy.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/download_manager.h"
#include "ui/base/dialogs/select_file_dialog.h"
using content::BrowserContext;
using content::BrowserThread;
using content::DownloadManager;
namespace {
base::LazyInstance<FilePath>::Leaky
g_last_save_path = LAZY_INSTANCE_INITIALIZER;
} // namespace
class DevToolsFileHelper::SaveAsDialog : public ui::SelectFileDialog::Listener,
public base::RefCounted<SaveAsDialog> {
public:
explicit SaveAsDialog(DevToolsFileHelper* helper)
: helper_(helper) {
select_file_dialog_ = ui::SelectFileDialog::Create(
this, new ChromeSelectFilePolicy(NULL));
}
void ResetHelper() {
helper_ = NULL;
}
void Show(const std::string& url,
const FilePath& initial_path,
const std::string& content) {
AddRef(); // Balanced in the three listener outcomes.
url_ = url;
content_ = content;
select_file_dialog_->SelectFile(ui::SelectFileDialog::SELECT_SAVEAS_FILE,
string16(),
initial_path,
NULL,
0,
FILE_PATH_LITERAL(""),
NULL,
NULL);
}
// ui::SelectFileDialog::Listener implementation.
virtual void FileSelected(const FilePath& path,
int index, void* params) {
if (helper_)
helper_->FileSelected(url_, path, content_);
Release(); // Balanced in ::Show.
}
virtual void MultiFilesSelected(
const std::vector<FilePath>& files, void* params) {
Release(); // Balanced in ::Show.
NOTREACHED() << "Should not be able to select multiple files";
}
virtual void FileSelectionCanceled(void* params) {
Release(); // Balanced in ::Show.
}
private:
friend class base::RefCounted<SaveAsDialog>;
virtual ~SaveAsDialog() {}
scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
std::string url_;
std::string content_;
DevToolsFileHelper* helper_;
};
// static
void DevToolsFileHelper::WriteFile(const FilePath& path,
const std::string& content) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
DCHECK(!path.empty());
file_util::WriteFile(path, content.c_str(), content.length());
}
// static
void DevToolsFileHelper::AppendToFile(const FilePath& path,
const std::string& content) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
DCHECK(!path.empty());
file_util::AppendToFile(path, content.c_str(), content.length());
}
DevToolsFileHelper::DevToolsFileHelper(Profile* profile, Delegate* delegate)
: profile_(profile),
delegate_(delegate) {
}
DevToolsFileHelper::~DevToolsFileHelper() {
if (save_as_dialog_)
save_as_dialog_->ResetHelper();
}
void DevToolsFileHelper::Save(const std::string& url,
const std::string& content,
bool save_as) {
PathsMap::iterator it = saved_files_.find(url);
if (it != saved_files_.end() && !save_as) {
FileSelected(url, it->second, content);
return;
}
if (save_as_dialog_)
save_as_dialog_->ResetHelper();
const DictionaryValue* file_map =
profile_->GetPrefs()->GetDictionary(prefs::kDevToolsEditedFiles);
FilePath initial_path;
const Value* path_value;
if (file_map->Get(base::MD5String(url), &path_value))
base::GetValueAsFilePath(*path_value, &initial_path);
if (initial_path.empty()) {
GURL gurl(url);
std::string suggested_file_name = gurl.is_valid() ?
gurl.ExtractFileName() : url;
if (suggested_file_name.length() > 20)
suggested_file_name = suggested_file_name.substr(0, 20);
if (!g_last_save_path.Pointer()->empty()) {
initial_path = g_last_save_path.Pointer()->DirName().AppendASCII(
suggested_file_name);
} else {
FilePath download_path = DownloadPrefs::FromDownloadManager(
BrowserContext::GetDownloadManager(profile_))->DownloadPath();
initial_path = download_path.AppendASCII(suggested_file_name);
}
}
save_as_dialog_ = new SaveAsDialog(this);
save_as_dialog_->Show(url, initial_path, content);
}
void DevToolsFileHelper::Append(const std::string& url,
const std::string& content) {
PathsMap::iterator it = saved_files_.find(url);
if (it == saved_files_.end())
return;
delegate_->AppendedTo(url);
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&DevToolsFileHelper::AppendToFile,
it->second,
content));
}
void DevToolsFileHelper::FileSelected(const std::string& url,
const FilePath& path,
const std::string& content) {
*g_last_save_path.Pointer() = path;
saved_files_[url] = path;
DictionaryPrefUpdate update(profile_->GetPrefs(),
prefs::kDevToolsEditedFiles);
DictionaryValue* files_map = update.Get();
files_map->SetWithoutPathExpansion(base::MD5String(url),
base::CreateFilePathValue(path));
delegate_->FileSavedAs(url);
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&DevToolsFileHelper::WriteFile,
path,
content));
}