1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/webui/slideshow_ui.h"
6
7#include "base/callback.h"
8#include "base/memory/singleton.h"
9#include "base/memory/weak_ptr.h"
10#include "base/message_loop.h"
11#include "base/path_service.h"
12#include "base/string_piece.h"
13#include "base/string_util.h"
14#include "base/threading/thread.h"
15#include "base/time.h"
16#include "base/utf_string_conversions.h"
17#include "base/values.h"
18#include "chrome/browser/history/history_types.h"
19#include "chrome/browser/metrics/user_metrics.h"
20#include "chrome/browser/profiles/profile.h"
21#include "chrome/browser/ui/webui/favicon_source.h"
22#include "chrome/common/chrome_paths.h"
23#include "chrome/common/jstemplate_builder.h"
24#include "chrome/common/url_constants.h"
25#include "content/browser/browser_thread.h"
26#include "content/browser/tab_contents/tab_contents.h"
27#include "grit/browser_resources.h"
28#include "grit/chromium_strings.h"
29#include "grit/generated_resources.h"
30#include "grit/locale_settings.h"
31#include "net/base/directory_lister.h"
32#include "net/base/escape.h"
33#include "ui/base/resource/resource_bundle.h"
34
35static const char kPropertyPath[] = "path";
36static const char kPropertyTitle[] = "title";
37static const char kPropertyOffset[] = "currentOffset";
38static const char kPropertyDirectory[] = "isDirectory";
39
40class SlideshowUIHTMLSource : public ChromeURLDataManager::DataSource {
41 public:
42  SlideshowUIHTMLSource();
43
44  // Called when the network layer has requested a resource underneath
45  // the path we registered.
46  virtual void StartDataRequest(const std::string& path,
47                                bool is_incognito,
48                                int request_id);
49  virtual std::string GetMimeType(const std::string&) const {
50    return "text/html";
51  }
52
53 private:
54  ~SlideshowUIHTMLSource() {}
55
56  DISALLOW_COPY_AND_ASSIGN(SlideshowUIHTMLSource);
57};
58
59// The handler for Javascript messages related to the "slideshow" view.
60class SlideshowHandler : public net::DirectoryLister::DirectoryListerDelegate,
61                         public WebUIMessageHandler,
62                         public base::SupportsWeakPtr<SlideshowHandler> {
63 public:
64  SlideshowHandler();
65  virtual ~SlideshowHandler();
66
67  // Init work after Attach.
68  void Init();
69
70  // DirectoryLister::DirectoryListerDelegate methods:
71  virtual void OnListFile(
72      const net::DirectoryLister::DirectoryListerData& data);
73  virtual void OnListDone(int error);
74
75  // WebUIMessageHandler implementation.
76  virtual WebUIMessageHandler* Attach(WebUI* web_ui);
77  virtual void RegisterMessages();
78
79  void GetChildrenForPath(const FilePath& path, bool is_refresh);
80
81  // Callback for the "getChildren" message.
82  void HandleGetChildren(const ListValue* args);
83
84  void HandleRefreshDirectory(const ListValue* args);
85
86 private:
87  bool PathIsImageFile(const char* filename);
88
89  scoped_ptr<ListValue> filelist_value_;
90  FilePath currentpath_;
91  FilePath originalpath_;
92  Profile* profile_;
93  int counter_;
94  int currentOffset_;
95  scoped_refptr<net::DirectoryLister> lister_;
96  bool is_refresh_;
97
98  DISALLOW_COPY_AND_ASSIGN(SlideshowHandler);
99};
100
101////////////////////////////////////////////////////////////////////////////////
102//
103// SlideshowHTMLSource
104//
105////////////////////////////////////////////////////////////////////////////////
106
107SlideshowUIHTMLSource::SlideshowUIHTMLSource()
108    : DataSource(chrome::kChromeUISlideshowHost, MessageLoop::current()) {
109}
110
111void SlideshowUIHTMLSource::StartDataRequest(const std::string& path,
112                                              bool is_incognito,
113                                              int request_id) {
114  DictionaryValue localized_strings;
115  // TODO(dhg): Add stirings to localized strings, also add more strings
116  // that are currently hardcoded.
117  SetFontAndTextDirection(&localized_strings);
118
119  static const base::StringPiece slideshow_html(
120      ResourceBundle::GetSharedInstance().GetRawDataResource(
121          IDR_SLIDESHOW_HTML));
122  const std::string full_html = jstemplate_builder::GetI18nTemplateHtml(
123      slideshow_html, &localized_strings);
124
125  scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
126  html_bytes->data.resize(full_html.size());
127  std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
128
129  SendResponse(request_id, html_bytes);
130}
131
132////////////////////////////////////////////////////////////////////////////////
133//
134// SlideshowHandler
135//
136////////////////////////////////////////////////////////////////////////////////
137SlideshowHandler::SlideshowHandler()
138    : profile_(NULL),
139      is_refresh_(false) {
140  lister_ = NULL;
141}
142
143SlideshowHandler::~SlideshowHandler() {
144  if (lister_.get()) {
145    lister_->Cancel();
146    lister_->set_delegate(NULL);
147  }
148}
149
150WebUIMessageHandler* SlideshowHandler::Attach(WebUI* web_ui) {
151  profile_ = web_ui->GetProfile();
152  // Create our favicon data source.
153  profile_->GetChromeURLDataManager()->AddDataSource(
154      new FaviconSource(profile_));
155  return WebUIMessageHandler::Attach(web_ui);
156}
157
158void SlideshowHandler::Init() {
159}
160
161void SlideshowHandler::RegisterMessages() {
162  web_ui_->RegisterMessageCallback("getChildren",
163      NewCallback(this, &SlideshowHandler::HandleGetChildren));
164  web_ui_->RegisterMessageCallback("refreshDirectory",
165      NewCallback(this, &SlideshowHandler::HandleRefreshDirectory));
166}
167
168void SlideshowHandler::HandleRefreshDirectory(const ListValue* args) {
169#if defined(OS_CHROMEOS)
170  std::string path = UTF16ToUTF8(ExtractStringValue(args));
171  GetChildrenForPath(FilePath(path), true);
172#endif
173}
174
175void SlideshowHandler::GetChildrenForPath(const FilePath& path,
176                                          bool is_refresh) {
177  filelist_value_.reset(new ListValue());
178  currentpath_ = path;
179
180  if (lister_.get()) {
181    lister_->Cancel();
182    lister_->set_delegate(NULL);
183    lister_ = NULL;
184  }
185
186  is_refresh_ = is_refresh;
187  if (file_util::EnsureEndsWithSeparator(&currentpath_) &&
188      currentpath_.IsAbsolute()) {
189    lister_ = new net::DirectoryLister(currentpath_, this);
190  } else {
191    originalpath_ = currentpath_;
192    currentpath_ = currentpath_.DirName();
193    lister_ = new net::DirectoryLister(currentpath_, this);
194  }
195  counter_ = 0;
196  currentOffset_ = -1;
197  lister_->Start();
198}
199
200void SlideshowHandler::HandleGetChildren(const ListValue* args) {
201#if defined(OS_CHROMEOS)
202  filelist_value_.reset(new ListValue());
203  std::string path = UTF16ToUTF8(ExtractStringValue(args));
204  GetChildrenForPath(FilePath(path), false);
205#endif
206}
207
208bool SlideshowHandler::PathIsImageFile(const char* filename) {
209#if defined(OS_CHROMEOS)
210  FilePath file = FilePath(filename);
211  std::string ext = file.Extension();
212  ext = StringToLowerASCII(ext);
213  if (ext == ".jpg" ||
214      ext == ".jpeg" ||
215      ext == ".png" ||
216      ext == ".gif") {
217    return true;
218  } else {
219    return false;
220  }
221#else
222  return false;
223#endif
224}
225
226void SlideshowHandler::OnListFile(
227    const net::DirectoryLister::DirectoryListerData& data) {
228#if defined(OS_CHROMEOS)
229  if (data.info.filename[0] == '.') {
230    return;
231  }
232  if (!PathIsImageFile(data.info.filename.c_str())) {
233    return;
234  }
235
236  DictionaryValue* file_value = new DictionaryValue();
237
238  file_value->SetString(kPropertyTitle, data.info.filename);
239  file_value->SetString(kPropertyPath,
240                        currentpath_.Append(data.info.filename).value());
241  file_value->SetBoolean(kPropertyDirectory, S_ISDIR(data.info.stat.st_mode));
242  filelist_value_->Append(file_value);
243  std::string val;
244  file_value->GetString(kPropertyTitle, &val);
245  if (val == originalpath_.BaseName().value()) {
246    currentOffset_ = counter_;
247  }
248  counter_++;
249#endif
250}
251
252void SlideshowHandler::OnListDone(int error) {
253  DictionaryValue info_value;
254  counter_ = 0;
255  if (!(file_util::EnsureEndsWithSeparator(&originalpath_) &&
256        originalpath_.IsAbsolute()) &&
257      currentOffset_ != -1) {
258    info_value.SetInteger(kPropertyOffset, currentOffset_);
259  }
260  if (is_refresh_) {
261    info_value.SetString("functionCall", "refresh");
262  } else {
263    info_value.SetString("functionCall", "getChildren");
264  }
265  info_value.SetString(kPropertyPath, currentpath_.value());
266  web_ui_->CallJavascriptFunction("browseFileResult",
267                                  info_value, *(filelist_value_.get()));
268}
269
270////////////////////////////////////////////////////////////////////////////////
271//
272// SlideshowUI
273//
274////////////////////////////////////////////////////////////////////////////////
275
276SlideshowUI::SlideshowUI(TabContents* contents) : WebUI(contents) {
277  SlideshowHandler* handler = new SlideshowHandler();
278  AddMessageHandler((handler)->Attach(this));
279  handler->Init();
280  SlideshowUIHTMLSource* html_source = new SlideshowUIHTMLSource();
281
282  // Set up the chrome://slideshow/ source.
283  contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
284}
285