| Index: chrome/browser/extensions/extension_history_api.cc
|
| ===================================================================
|
| --- chrome/browser/extensions/extension_history_api.cc (revision 0)
|
| +++ chrome/browser/extensions/extension_history_api.cc (revision 0)
|
| @@ -0,0 +1,366 @@
|
| +// 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 "chrome/browser/extensions/extension_history_api.h"
|
| +
|
| +#include "base/json/json_writer.h"
|
| +#include "base/message_loop.h"
|
| +#include "base/string_util.h"
|
| +#include "base/task.h"
|
| +#include "base/values.h"
|
| +#include "chrome/browser/extensions/extension_history_api_constants.h"
|
| +#include "chrome/browser/extensions/extension_message_service.h"
|
| +#include "chrome/browser/history/history.h"
|
| +#include "chrome/browser/history/history_types.h"
|
| +#include "chrome/browser/profile.h"
|
| +#include "chrome/common/notification_type.h"
|
| +#include "chrome/common/notification_service.h"
|
| +
|
| +namespace keys = extension_history_api_constants;
|
| +
|
| +namespace {
|
| +
|
| +double MilliSecondsFromTime(const base::Time& time) {
|
| + return 1000 * time.ToDoubleT();
|
| +}
|
| +
|
| +void GetHistoryItemDictionary(const history::URLRow& row,
|
| + DictionaryValue* value) {
|
| + value->SetString(keys::kIdKey, Int64ToString(row.id()));
|
| + value->SetString(keys::kUrlKey, row.url().spec());
|
| + value->SetString(keys::kTitleKey, row.title());
|
| + value->SetReal(keys::kLastVisitdKey, MilliSecondsFromTime(row.last_visit()));
|
| + value->SetInteger(keys::kTypedCountKey, row.typed_count());
|
| + value->SetInteger(keys::kVisitCountKey, row.visit_count());
|
| +}
|
| +
|
| +void AddHistoryNode(const history::URLRow& row, ListValue* list) {
|
| + DictionaryValue* dict = new DictionaryValue();
|
| + GetHistoryItemDictionary(row, dict);
|
| + list->Append(dict);
|
| +}
|
| +
|
| +void GetVisitInfoDictionary(const history::VisitRow& row,
|
| + DictionaryValue* value) {
|
| + value->SetString(keys::kIdKey, Int64ToString(row.url_id));
|
| + value->SetString(keys::kVisitId, Int64ToString(row.visit_id));
|
| + value->SetReal(keys::kVisitTime, MilliSecondsFromTime(row.visit_time));
|
| + value->SetString(keys::kReferringVisitId,
|
| + Int64ToString(row.referring_visit));
|
| + value->SetInteger(keys::kTransition,
|
| + row.transition && PageTransition::CORE_MASK);
|
| +}
|
| +
|
| +void AddVisitNode(const history::VisitRow& row, ListValue* list) {
|
| + DictionaryValue* dict = new DictionaryValue();
|
| + GetVisitInfoDictionary(row, dict);
|
| + list->Append(dict);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +ExtensionHistoryEventRouter* ExtensionHistoryEventRouter::GetInstance() {
|
| + return Singleton<ExtensionHistoryEventRouter>::get();
|
| +}
|
| +
|
| +void ExtensionHistoryEventRouter::ObserveProfile(Profile* profile) {
|
| + NotificationSource source = Source<Profile>(profile);
|
| + if (profiles_.find(source.map_key()) == profiles_.end())
|
| + profiles_[source.map_key()] = profile;
|
| +
|
| + if (registrar_.IsEmpty()) {
|
| + registrar_.Add(this,
|
| + NotificationType::HISTORY_URL_VISITED,
|
| + NotificationService::AllSources());
|
| + registrar_.Add(this,
|
| + NotificationType::HISTORY_URLS_DELETED,
|
| + NotificationService::AllSources());
|
| + }
|
| +}
|
| +
|
| +void ExtensionHistoryEventRouter::Observe(NotificationType type,
|
| + const NotificationSource& source,
|
| + const NotificationDetails& details) {
|
| + ProfileMap::iterator it = profiles_.find(source.map_key());
|
| + if (it != profiles_.end()) {
|
| + Profile* profile = it->second;
|
| + switch (type.value) {
|
| + case NotificationType::HISTORY_URL_VISITED:
|
| + HistoryUrlVisited(
|
| + profile,
|
| + Details<const history::URLVisitedDetails>(details).ptr());
|
| + break;
|
| + case NotificationType::HISTORY_URLS_DELETED:
|
| + HistoryUrlsRemoved(
|
| + profile,
|
| + Details<const history::URLsDeletedDetails>(details).ptr());
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| + }
|
| +}
|
| +
|
| +void ExtensionHistoryEventRouter::HistoryUrlVisited(
|
| + Profile* profile,
|
| + const history::URLVisitedDetails* details) {
|
| + ListValue args;
|
| + DictionaryValue* dict = new DictionaryValue();
|
| + GetHistoryItemDictionary(details->row, dict);
|
| + args.Append(dict);
|
| +
|
| + std::string json_args;
|
| + base::JSONWriter::Write(&args, false, &json_args);
|
| + DispatchEvent(profile, keys::kOnVisited, json_args);
|
| +}
|
| +
|
| +void ExtensionHistoryEventRouter::HistoryUrlsRemoved(
|
| + Profile* profile,
|
| + const history::URLsDeletedDetails* details) {
|
| + ListValue args;
|
| + DictionaryValue* dict = new DictionaryValue();
|
| + dict->SetBoolean(keys::kAllHistoryKey, details->all_history);
|
| + ListValue* urls = new ListValue();
|
| + for (std::set<GURL>::const_iterator iterator = details->urls.begin();
|
| + iterator != details->urls.end();
|
| + ++iterator) {
|
| + urls->Append(new StringValue(iterator->spec()));
|
| + }
|
| + dict->Set(keys::kUrlsKey, urls);
|
| + args.Append(dict);
|
| +
|
| + std::string json_args;
|
| + base::JSONWriter::Write(&args, false, &json_args);
|
| + DispatchEvent(profile, keys::kOnVisitRemoved, json_args);
|
| +}
|
| +
|
| +void ExtensionHistoryEventRouter::DispatchEvent(Profile* profile,
|
| + const char* event_name,
|
| + const std::string& json_args) {
|
| + if (profile && profile->GetExtensionMessageService()) {
|
| + profile->GetExtensionMessageService()->
|
| + DispatchEventToRenderers(event_name, json_args);
|
| + }
|
| +}
|
| +
|
| +void HistoryFunction::Run() {
|
| + if (!RunImpl()) {
|
| + SendResponse(false);
|
| + }
|
| +}
|
| +
|
| +bool HistoryFunction::GetUrlFromValue(Value* value, GURL* url) {
|
| + std::string url_string;
|
| + if (!value->GetAsString(&url_string)) {
|
| + bad_message_ = true;
|
| + return false;
|
| + }
|
| +
|
| + GURL temp_url(url_string);
|
| + if (!temp_url.is_valid()) {
|
| + error_ = keys::kInvalidUrlError;
|
| + return false;
|
| + }
|
| + url->Swap(&temp_url);
|
| + return true;
|
| +}
|
| +
|
| +bool HistoryFunction::GetTimeFromValue(Value* value, base::Time* time) {
|
| + double ms_from_epoch = 0;
|
| + if (!value->GetAsReal(&ms_from_epoch)) {
|
| + return false;
|
| + }
|
| + // The history service has seconds resolution, while javascript Date() has
|
| + // milliseconds resolution.
|
| + double seconds_from_epoch = ms_from_epoch / 1000;
|
| + *time = base::Time::FromDoubleT(seconds_from_epoch);
|
| + return true;
|
| +}
|
| +
|
| +bool HistoryFunctionWithCallback::RunImpl() {
|
| + AddRef(); // Balanced in SendAysncRepose() and below.
|
| + bool retval = RunAsyncImpl();
|
| + if (false == retval)
|
| + Release();
|
| + return retval;
|
| +}
|
| +
|
| +void HistoryFunctionWithCallback::SendAsyncResponse() {
|
| + MessageLoop::current()->PostTask(
|
| + FROM_HERE,
|
| + NewRunnableMethod(
|
| + this,
|
| + &HistoryFunctionWithCallback::SendResponseToCallback));
|
| +}
|
| +
|
| +void HistoryFunctionWithCallback::SendResponseToCallback() {
|
| + SendResponse(true);
|
| + Release(); // Balanced in RunImpl().
|
| +}
|
| +
|
| +bool GetVisitsHistoryFunction::RunAsyncImpl() {
|
| + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
|
| + DictionaryValue* json = static_cast<DictionaryValue*>(args_);
|
| +
|
| + Value* value;
|
| + EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kUrlKey, &value));
|
| +
|
| + GURL url;
|
| + if (!GetUrlFromValue(value, &url))
|
| + return false;
|
| +
|
| + HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
|
| + hs->QueryURL(url,
|
| + true, // Retrieve full history of a URL.
|
| + &cancelable_consumer_,
|
| + NewCallback(this, &GetVisitsHistoryFunction::QueryComplete));
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void GetVisitsHistoryFunction::QueryComplete(
|
| + HistoryService::Handle request_service,
|
| + bool success,
|
| + const history::URLRow* url_row,
|
| + history::VisitVector* visits) {
|
| + ListValue* list = new ListValue();
|
| + if (visits && !visits->empty()) {
|
| + for (history::VisitVector::iterator iterator = visits->begin();
|
| + iterator != visits->end();
|
| + ++iterator) {
|
| + AddVisitNode(*iterator, list);
|
| + }
|
| + }
|
| + result_.reset(list);
|
| + SendAsyncResponse();
|
| +}
|
| +
|
| +bool SearchHistoryFunction::RunAsyncImpl() {
|
| + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
|
| + DictionaryValue* json = static_cast<DictionaryValue*>(args_);
|
| +
|
| + // Initialize the HistoryQuery
|
| + std::wstring search_text;
|
| + EXTENSION_FUNCTION_VALIDATE(json->GetString(keys::kSearchKey, &search_text));
|
| +
|
| + history::QueryOptions options;
|
| + options.most_recent_visit_only = true;
|
| + options.SetRecentDayRange(1);
|
| + options.max_count = 100;
|
| +
|
| + if (json->HasKey(keys::kStartTimeKey)) { // Optional.
|
| + Value* value;
|
| + EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kStartTimeKey, &value));
|
| + EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &options.begin_time));
|
| + }
|
| + if (json->HasKey(keys::kEndTimeKey)) { // Optional.
|
| + Value* value;
|
| + EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kEndTimeKey, &value));
|
| + EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &options.end_time));
|
| + }
|
| + if (json->HasKey(keys::kMaxResultsKey)) { // Optional.
|
| + EXTENSION_FUNCTION_VALIDATE(json->GetInteger(keys::kMaxResultsKey,
|
| + &options.max_count));
|
| + }
|
| +
|
| + HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
|
| + hs->QueryHistory(search_text, options, &cancelable_consumer_,
|
| + NewCallback(this, &SearchHistoryFunction::SearchComplete));
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void SearchHistoryFunction::SearchComplete(
|
| + HistoryService::Handle request_handle,
|
| + history::QueryResults* results) {
|
| + ListValue* list = new ListValue();
|
| + if (results && !results->empty()) {
|
| + for (history::QueryResults::URLResultVector::const_iterator iterator =
|
| + results->begin();
|
| + iterator != results->end();
|
| + ++iterator) {
|
| + AddHistoryNode(**iterator, list);
|
| + }
|
| + }
|
| + result_.reset(list);
|
| + SendAsyncResponse();
|
| +}
|
| +
|
| +bool AddUrlHistoryFunction::RunImpl() {
|
| + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
|
| + DictionaryValue* json = static_cast<DictionaryValue*>(args_);
|
| +
|
| + Value* value;
|
| + EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kUrlKey, &value));
|
| +
|
| + GURL url;
|
| + if (!GetUrlFromValue(value, &url))
|
| + return false;
|
| +
|
| + HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
|
| + hs->AddPage(url);
|
| +
|
| + SendResponse(true);
|
| + return true;
|
| +}
|
| +
|
| +bool DeleteUrlHistoryFunction::RunImpl() {
|
| + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
|
| + DictionaryValue* json = static_cast<DictionaryValue*>(args_);
|
| +
|
| + Value* value;
|
| + EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kUrlKey, &value));
|
| +
|
| + GURL url;
|
| + if (!GetUrlFromValue(value, &url))
|
| + return false;
|
| +
|
| + HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
|
| + hs->DeleteURL(url);
|
| +
|
| + SendResponse(true);
|
| + return true;
|
| +}
|
| +
|
| +bool DeleteRangeHistoryFunction::RunAsyncImpl() {
|
| + EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_DICTIONARY));
|
| + DictionaryValue* json = static_cast<DictionaryValue*>(args_);
|
| +
|
| + Value* value = NULL;
|
| + EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kStartTimeKey, &value));
|
| + base::Time begin_time;
|
| + EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &begin_time));
|
| +
|
| + EXTENSION_FUNCTION_VALIDATE(json->Get(keys::kEndTimeKey, &value));
|
| + base::Time end_time;
|
| + EXTENSION_FUNCTION_VALIDATE(GetTimeFromValue(value, &end_time));
|
| +
|
| + HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
|
| + hs->ExpireHistoryBetween(
|
| + begin_time,
|
| + end_time,
|
| + &cancelable_consumer_,
|
| + NewCallback(this, &DeleteRangeHistoryFunction::DeleteComplete));
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void DeleteRangeHistoryFunction::DeleteComplete() {
|
| + SendAsyncResponse();
|
| +}
|
| +
|
| +bool DeleteAllHistoryFunction::RunAsyncImpl() {
|
| + HistoryService* hs = profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
|
| + hs->ExpireHistoryBetween(
|
| + base::Time::FromDoubleT(0), // From the beginning of the epoch.
|
| + base::Time::Now(), // To the current time.
|
| + &cancelable_consumer_,
|
| + NewCallback(this, &DeleteAllHistoryFunction::DeleteComplete));
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void DeleteAllHistoryFunction::DeleteComplete() {
|
| + SendAsyncResponse();
|
| +}
|
|
|
| Property changes on: chrome\browser\extensions\extension_history_api.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|