<commit_before>// 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/downloads_dom_handler.h"

#include <algorithm>
#include <functional>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/singleton.h"
#include "base/string_piece.h"
#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_history.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
#include "chrome/browser/ui/webui/fileicon_source.h"
#include "chrome/browser/ui/webui/fileicon_source_cros.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 "content/browser/user_metrics.h"
#include "grit/generated_resources.h"
#include "ui/gfx/image/image.h"

namespace {

// Maximum number of downloads to show. TODO(glen): Remove this and instead
// stuff the downloads down the pipe slowly.
static const int kMaxDownloads = 150;

// Sort DownloadItems into descending order by their start time.
class DownloadItemSorter : public std::binary_function<DownloadItem*,
                                                       DownloadItem*,
                                                       bool> {
 public:
  bool operator()(const DownloadItem* lhs, const DownloadItem* rhs) {
    return lhs->start_time() > rhs->start_time();
  }
};

}  // namespace

DownloadsDOMHandler::DownloadsDOMHandler(DownloadManager* dlm)
    : search_text_(),
      download_manager_(dlm),
      callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
  // Create our fileicon data source.
  dlm->profile()->GetChromeURLDataManager()->AddDataSource(
#if defined(OS_CHROMEOS)
      new FileIconSourceCros());
#else
      new FileIconSource());
#endif  // OS_CHROMEOS
}

DownloadsDOMHandler::~DownloadsDOMHandler() {
  ClearDownloadItems();
  download_manager_->RemoveObserver(this);
}

// DownloadsDOMHandler, public: -----------------------------------------------

void DownloadsDOMHandler::Init() {
  download_manager_->AddObserver(this);
}

void DownloadsDOMHandler::RegisterMessages() {
  web_ui_->RegisterMessageCallback("getDownloads",
      NewCallback(this, &DownloadsDOMHandler::HandleGetDownloads));
  web_ui_->RegisterMessageCallback("openFile",
      NewCallback(this, &DownloadsDOMHandler::HandleOpenFile));

  web_ui_->RegisterMessageCallback("drag",
      NewCallback(this, &DownloadsDOMHandler::HandleDrag));

  web_ui_->RegisterMessageCallback("saveDangerous",
      NewCallback(this, &DownloadsDOMHandler::HandleSaveDangerous));
  web_ui_->RegisterMessageCallback("discardDangerous",
      NewCallback(this, &DownloadsDOMHandler::HandleDiscardDangerous));
  web_ui_->RegisterMessageCallback("show",
      NewCallback(this, &DownloadsDOMHandler::HandleShow));
  web_ui_->RegisterMessageCallback("togglepause",
      NewCallback(this, &DownloadsDOMHandler::HandlePause));
  web_ui_->RegisterMessageCallback("resume",
      NewCallback(this, &DownloadsDOMHandler::HandlePause));
  web_ui_->RegisterMessageCallback("remove",
      NewCallback(this, &DownloadsDOMHandler::HandleRemove));
  web_ui_->RegisterMessageCallback("cancel",
      NewCallback(this, &DownloadsDOMHandler::HandleCancel));
  web_ui_->RegisterMessageCallback("clearAll",
      NewCallback(this, &DownloadsDOMHandler::HandleClearAll));
}

void DownloadsDOMHandler::OnDownloadUpdated(DownloadItem* download) {
  // Get the id for the download. Our downloads are sorted latest to first,
  // and the id is the index into that list. We should be careful of sync
  // errors between the UI and the download_items_ list (we may wish to use
  // something other than 'id').
  OrderedDownloads::iterator it = find(download_items_.begin(),
                                       download_items_.end(),
                                       download);
  if (it == download_items_.end())
    return;
  const int id = static_cast<int>(it - download_items_.begin());

  ListValue results_value;
  results_value.Append(download_util::CreateDownloadItemValue(download, id));
  web_ui_->CallJavascriptFunction("downloadUpdated", results_value);
}

// A download has started or been deleted. Query our DownloadManager for the
// current set of downloads.
void DownloadsDOMHandler::ModelChanged() {
  ClearDownloadItems();
  download_manager_->SearchDownloads(WideToUTF16(search_text_),
                                     &download_items_);
  sort(download_items_.begin(), download_items_.end(), DownloadItemSorter());

  // Add ourself to all download items as an observer.
  for (OrderedDownloads::iterator it = download_items_.begin();
       it != download_items_.end(); ++it) {
    if (static_cast<int>(it - download_items_.begin()) > kMaxDownloads)
      break;
    (*it)->AddObserver(this);
  }

  SendCurrentDownloads();
}

void DownloadsDOMHandler::HandleGetDownloads(const ListValue* args) {
  std::wstring new_search = UTF16ToWideHack(ExtractStringValue(args));
  if (search_text_.compare(new_search) != 0) {
    search_text_ = new_search;
    ModelChanged();
  } else {
    SendCurrentDownloads();
  }

  download_manager_->CheckForHistoryFilesRemoval();
}

void DownloadsDOMHandler::HandleOpenFile(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->OpenDownload();
}

void DownloadsDOMHandler::HandleDrag(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file) {
    IconManager* im = g_browser_process->icon_manager();
    gfx::Image* icon = im->LookupIcon(file->GetUserVerifiedFilePath(),
                                      IconLoader::NORMAL);
    gfx::NativeView view = web_ui_->tab_contents()->GetNativeView();
    download_util::DragDownload(file, icon, view);
  }
}

void DownloadsDOMHandler::HandleSaveDangerous(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    download_manager_->DangerousDownloadValidated(file);
}

void DownloadsDOMHandler::HandleDiscardDangerous(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
}

void DownloadsDOMHandler::HandleShow(const ListValue* args) {<commit_msg>Fix drag-hover tab-selection with files dragged from the download manager.<commit_after>// 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/downloads_dom_handler.h"

#include <algorithm>
#include <functional>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/singleton.h"
#include "base/string_piece.h"
#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_history.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
#include "chrome/browser/ui/webui/fileicon_source.h"
#include "chrome/browser/ui/webui/fileicon_source_cros.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 "content/browser/user_metrics.h"
#include "grit/generated_resources.h"
#include "ui/gfx/image/image.h"

namespace {

// Maximum number of downloads to show. TODO(glen): Remove this and instead
// stuff the downloads down the pipe slowly.
static const int kMaxDownloads = 150;

// Sort DownloadItems into descending order by their start time.
class DownloadItemSorter : public std::binary_function<DownloadItem*,
                                                       DownloadItem*,
                                                       bool> {
 public:
  bool operator()(const DownloadItem* lhs, const DownloadItem* rhs) {
    return lhs->start_time() > rhs->start_time();
  }
};

}  // namespace

DownloadsDOMHandler::DownloadsDOMHandler(DownloadManager* dlm)
    : search_text_(),
      download_manager_(dlm),
      callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
  // Create our fileicon data source.
  dlm->profile()->GetChromeURLDataManager()->AddDataSource(
#if defined(OS_CHROMEOS)
      new FileIconSourceCros());
#else
      new FileIconSource());
#endif  // OS_CHROMEOS
}

DownloadsDOMHandler::~DownloadsDOMHandler() {
  ClearDownloadItems();
  download_manager_->RemoveObserver(this);
}

// DownloadsDOMHandler, public: -----------------------------------------------

void DownloadsDOMHandler::Init() {
  download_manager_->AddObserver(this);
}

void DownloadsDOMHandler::RegisterMessages() {
  web_ui_->RegisterMessageCallback("getDownloads",
      NewCallback(this, &DownloadsDOMHandler::HandleGetDownloads));
  web_ui_->RegisterMessageCallback("openFile",
      NewCallback(this, &DownloadsDOMHandler::HandleOpenFile));

  web_ui_->RegisterMessageCallback("drag",
      NewCallback(this, &DownloadsDOMHandler::HandleDrag));

  web_ui_->RegisterMessageCallback("saveDangerous",
      NewCallback(this, &DownloadsDOMHandler::HandleSaveDangerous));
  web_ui_->RegisterMessageCallback("discardDangerous",
      NewCallback(this, &DownloadsDOMHandler::HandleDiscardDangerous));
  web_ui_->RegisterMessageCallback("show",
      NewCallback(this, &DownloadsDOMHandler::HandleShow));
  web_ui_->RegisterMessageCallback("togglepause",
      NewCallback(this, &DownloadsDOMHandler::HandlePause));
  web_ui_->RegisterMessageCallback("resume",
      NewCallback(this, &DownloadsDOMHandler::HandlePause));
  web_ui_->RegisterMessageCallback("remove",
      NewCallback(this, &DownloadsDOMHandler::HandleRemove));
  web_ui_->RegisterMessageCallback("cancel",
      NewCallback(this, &DownloadsDOMHandler::HandleCancel));
  web_ui_->RegisterMessageCallback("clearAll",
      NewCallback(this, &DownloadsDOMHandler::HandleClearAll));
}

void DownloadsDOMHandler::OnDownloadUpdated(DownloadItem* download) {
  // Get the id for the download. Our downloads are sorted latest to first,
  // and the id is the index into that list. We should be careful of sync
  // errors between the UI and the download_items_ list (we may wish to use
  // something other than 'id').
  OrderedDownloads::iterator it = find(download_items_.begin(),
                                       download_items_.end(),
                                       download);
  if (it == download_items_.end())
    return;
  const int id = static_cast<int>(it - download_items_.begin());

  ListValue results_value;
  results_value.Append(download_util::CreateDownloadItemValue(download, id));
  web_ui_->CallJavascriptFunction("downloadUpdated", results_value);
}

// A download has started or been deleted. Query our DownloadManager for the
// current set of downloads.
void DownloadsDOMHandler::ModelChanged() {
  ClearDownloadItems();
  download_manager_->SearchDownloads(WideToUTF16(search_text_),
                                     &download_items_);
  sort(download_items_.begin(), download_items_.end(), DownloadItemSorter());

  // Add ourself to all download items as an observer.
  for (OrderedDownloads::iterator it = download_items_.begin();
       it != download_items_.end(); ++it) {
    if (static_cast<int>(it - download_items_.begin()) > kMaxDownloads)
      break;
    (*it)->AddObserver(this);
  }

  SendCurrentDownloads();
}

void DownloadsDOMHandler::HandleGetDownloads(const ListValue* args) {
  std::wstring new_search = UTF16ToWideHack(ExtractStringValue(args));
  if (search_text_.compare(new_search) != 0) {
    search_text_ = new_search;
    ModelChanged();
  } else {
    SendCurrentDownloads();
  }

  download_manager_->CheckForHistoryFilesRemoval();
}

void DownloadsDOMHandler::HandleOpenFile(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->OpenDownload();
}

void DownloadsDOMHandler::HandleDrag(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file) {
    IconManager* im = g_browser_process->icon_manager();
    gfx::Image* icon = im->LookupIcon(file->GetUserVerifiedFilePath(),
                                      IconLoader::NORMAL);
    gfx::NativeView view = web_ui_->tab_contents()->GetNativeView();
    {
      // Enable nested tasks during DnD, while |DragDownload()| blocks.
      MessageLoop::ScopedNestableTaskAllower allower(MessageLoop::current());
      download_util::DragDownload(file, icon, view);
    }
  }
}

void DownloadsDOMHandler::HandleSaveDangerous(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    download_manager_->DangerousDownloadValidated(file);
}

void DownloadsDOMHandler::HandleDiscardDangerous(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
}

void DownloadsDOMHandler::HandleShow(const ListValue* args) {
{'fraction_non_alphanumeric': 0.12264220726385087, 'fraction_numerical': 0.0017752792366299282, 'mean_word_length': 4.414497396876252, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 216, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2360512', 'n_tokens_mistral': 3936, 'n_tokens_neox': 3883, 'n_words': 779}