// Copyright (c) 2011 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/slideshow_ui.h"
#include "base/callback.h"
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/threading/thread.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/favicon_source.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "grit/browser_resources.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "net/base/directory_lister.h"
#include "net/base/escape.h"
#include "ui/base/resource/resource_bundle.h"
static const char kPropertyPath[] = "path";
static const char kPropertyTitle[] = "title";
static const char kPropertyOffset[] = "currentOffset";
static const char kPropertyDirectory[] = "isDirectory";
class SlideshowUIHTMLSource : public ChromeURLDataManager::DataSource {
public:
SlideshowUIHTMLSource();
// Called when the network layer has requested a resource underneath
// the path we registered.
virtual void StartDataRequest(const std::string& path,
bool is_incognito,
int request_id);
virtual std::string GetMimeType(const std::string&) const {
return "text/html";
}
private:
~SlideshowUIHTMLSource() {}
DISALLOW_COPY_AND_ASSIGN(SlideshowUIHTMLSource);
};
// The handler for Javascript messages related to the "slideshow" view.
class SlideshowHandler : public net::DirectoryLister::DirectoryListerDelegate,
public WebUIMessageHandler,
public base::SupportsWeakPtr<SlideshowHandler> {
public:
SlideshowHandler();
virtual ~SlideshowHandler();
// Init work after Attach.
void Init();
// DirectoryLister::DirectoryListerDelegate methods:
virtual void OnListFile(
const net::DirectoryLister::DirectoryListerData& data);
virtual void OnListDone(int error);
// WebUIMessageHandler implementation.
virtual WebUIMessageHandler* Attach(WebUI* web_ui);
virtual void RegisterMessages();
void GetChildrenForPath(const FilePath& path, bool is_refresh);
// Callback for the "getChildren" message.
void HandleGetChildren(const ListValue* args);
void HandleRefreshDirectory(const ListValue* args);
private:
bool PathIsImageFile(const char* filename);
scoped_ptr<ListValue> filelist_value_;
FilePath currentpath_;
FilePath originalpath_;
Profile* profile_;
int counter_;
int currentOffset_;
scoped_refptr<net::DirectoryLister> lister_;
bool is_refresh_;
DISALLOW_COPY_AND_ASSIGN(SlideshowHandler);
};
////////////////////////////////////////////////////////////////////////////////
//
// SlideshowHTMLSource
//
////////////////////////////////////////////////////////////////////////////////
SlideshowUIHTMLSource::SlideshowUIHTMLSource()
: DataSource(chrome::kChromeUISlideshowHost, MessageLoop::current()) {
}
void SlideshowUIHTMLSource::StartDataRequest(const std::string& path,
bool is_incognito,
int request_id) {
DictionaryValue localized_strings;
// TODO(dhg): Add stirings to localized strings, also add more strings
// that are currently hardcoded.
SetFontAndTextDirection(&localized_strings);
static const base::StringPiece slideshow_html(
ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_SLIDESHOW_HTML));
const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
slideshow_html, &localized_strings);
scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
html_bytes->data.resize(full_html.size());
std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
SendResponse(request_id, html_bytes);
}
////////////////////////////////////////////////////////////////////////////////
//
// SlideshowHandler
//
////////////////////////////////////////////////////////////////////////////////
SlideshowHandler::SlideshowHandler()
: profile_(NULL),
is_refresh_(false) {
lister_ = NULL;
}
SlideshowHandler::~SlideshowHandler() {
if (lister_.get()) {
lister_->Cancel();
lister_->set_delegate(NULL);
}
}
WebUIMessageHandler* SlideshowHandler::Attach(WebUI* web_ui) {
profile_ = web_ui->GetProfile();
// Create our favicon data source.
profile_->GetChromeURLDataManager()->AddDataSource(
new FaviconSource(profile_));
return WebUIMessageHandler::Attach(web_ui);
}
void SlideshowHandler::Init() {
}
void SlideshowHandler::RegisterMessages() {
web_ui_->RegisterMessageCallback("getChildren",
NewCallback(this, &SlideshowHandler::HandleGetChildren));
web_ui_->RegisterMessageCallback("refreshDirectory",
NewCallback(this, &SlideshowHandler::HandleRefreshDirectory));
}
void SlideshowHandler::HandleRefreshDirectory(const ListValue* args) {
#if defined(OS_CHROMEOS)
std::string path = UTF16ToUTF8(ExtractStringValue(args));
GetChildrenForPath(FilePath(path), true);
#endif
}
void SlideshowHandler::GetChildrenForPath(const FilePath& path,
bool is_refresh) {
filelist_value_.reset(new ListValue());
currentpath_ = path;
if (lister_.get()) {
lister_->Cancel();
lister_->set_delegate(NULL);
lister_ = NULL;
}
is_refresh_ = is_refresh;
if (file_util::EnsureEndsWithSeparator(¤tpath_) &&
currentpath_.IsAbsolute()) {
lister_ = new net::DirectoryLister(currentpath_, this);
} else {
originalpath_ = currentpath_;
currentpath_ = currentpath_.DirName();
lister_ = new net::DirectoryLister(currentpath_, this);
}
counter_ = 0;
currentOffset_ = -1;
lister_->Start();
}
void SlideshowHandler::HandleGetChildren(const ListValue* args) {
#if defined(OS_CHROMEOS)
filelist_value_.reset(new ListValue());
std::string path = UTF16ToUTF8(ExtractStringValue(args));
GetChildrenForPath(FilePath(path), false);
#endif
}
bool SlideshowHandler::PathIsImageFile(const char* filename) {
#if defined(OS_CHROMEOS)
FilePath file = FilePath(filename);
std::string ext = file.Extension();
ext = StringToLowerASCII(ext);
if (ext == ".jpg" ||
ext == ".jpeg" ||
ext == ".png" ||
ext == ".gif") {
return true;
} else {
return false;
}
#else
return false;
#endif
}
void SlideshowHandler::OnListFile(
const net::DirectoryLister::DirectoryListerData& data) {
#if defined(OS_CHROMEOS)
if (data.info.filename[0] == '.') {
return;
}
if (!PathIsImageFile(data.info.filename.c_str())) {
return;
}
DictionaryValue* file_value = new DictionaryValue();
file_value->SetString(kPropertyTitle, data.info.filename);
file_value->SetString(kPropertyPath,
currentpath_.Append(data.info.filename).value());
file_value->SetBoolean(kPropertyDirectory, S_ISDIR(data.info.stat.st_mode));
filelist_value_->Append(file_value);
std::string val;
file_value->GetString(kPropertyTitle, &val);
if (val == originalpath_.BaseName().value()) {
currentOffset_ = counter_;
}
counter_++;
#endif
}
void SlideshowHandler::OnListDone(int error) {
DictionaryValue info_value;
counter_ = 0;
if (!(file_util::EnsureEndsWithSeparator(&originalpath_) &&
originalpath_.IsAbsolute()) &&
currentOffset_ != -1) {
info_value.SetInteger(kPropertyOffset, currentOffset_);
}
if (is_refresh_) {
info_value.SetString("functionCall", "refresh");
} else {
info_value.SetString("functionCall", "getChildren");
}
info_value.SetString(kPropertyPath, currentpath_.value());
web_ui_->CallJavascriptFunction("browseFileResult",
info_value, *(filelist_value_.get()));
}
////////////////////////////////////////////////////////////////////////////////
//
// SlideshowUI
//
////////////////////////////////////////////////////////////////////////////////
SlideshowUI::SlideshowUI(TabContents* contents) : WebUI(contents) {
SlideshowHandler* handler = new SlideshowHandler();
AddMessageHandler((handler)->Attach(this));
handler->Init();
SlideshowUIHTMLSource* html_source = new SlideshowUIHTMLSource();
// Set up the chrome://slideshow/ source.
contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
}