diff options
18 files changed, 172 insertions, 23 deletions
diff --git a/chrome/browser/history/history.cc b/chrome/browser/history/history.cc index f869296..b765197 100644 --- a/chrome/browser/history/history.cc +++ b/chrome/browser/history/history.cc @@ -665,13 +665,14 @@ HistoryService::Handle HistoryService::QueryMostVisitedURLs( HistoryService::Handle HistoryService::QueryFilteredURLs( int result_count, const history::VisitFilter& filter, + bool extended_info, CancelableRequestConsumerBase* consumer, const QueryFilteredURLsCallback& callback) { return Schedule(PRIORITY_NORMAL, &HistoryBackend::QueryFilteredURLs, consumer, new history::QueryFilteredURLsRequest(callback), - result_count, filter); + result_count, filter, extended_info); } void HistoryService::Observe(int type, diff --git a/chrome/browser/history/history.h b/chrome/browser/history/history.h index 1d76789..dcdf1a5 100644 --- a/chrome/browser/history/history.h +++ b/chrome/browser/history/history.h @@ -385,9 +385,12 @@ class HistoryService : public CancelableRequestProvider, const QueryMostVisitedURLsCallback& callback); // Request the |result_count| URLs filtered and sorted based on the |filter|. + // If |extended_info| is enabled, additional data will be provided in the + // results. Handle QueryFilteredURLs( int result_count, const history::VisitFilter& filter, + bool extended_info, CancelableRequestConsumerBase* consumer, const QueryFilteredURLsCallback& callback); diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc index 90a4549..21c21e3 100644 --- a/chrome/browser/history/history_backend.cc +++ b/chrome/browser/history/history_backend.cc @@ -1460,7 +1460,8 @@ void HistoryBackend::QueryMostVisitedURLs( void HistoryBackend::QueryFilteredURLs( scoped_refptr<QueryFilteredURLsRequest> request, int result_count, - const history::VisitFilter& filter) { + const history::VisitFilter& filter, + bool extended_info) { if (request->canceled()) return; @@ -1544,6 +1545,22 @@ void HistoryBackend::QueryFilteredURLs( for (size_t i = 0; i < data.size(); ++i) { PageUsageData* current_data = data[i]; FilteredURL url(*current_data); + + if (extended_info) { + VisitVector visits; + db_->GetVisitsForURL(current_data->GetID(), &visits); + if (visits.size() > 0) { + url.extended_info.total_visits = visits.size(); + for (size_t i = 0; i < visits.size(); ++i) { + url.extended_info.duration_opened += + visits[i].visit_duration.InSeconds(); + if (visits[i].visit_time > url.extended_info.last_visit_time) { + url.extended_info.last_visit_time = visits[i].visit_time; + } + } + // TODO(macourteau): implement the url.debug.visits stat. + } + } result.push_back(url); } diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h index 5418764..9466dd7 100644 --- a/chrome/browser/history/history_backend.h +++ b/chrome/browser/history/history_backend.h @@ -196,10 +196,12 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>, // Request the |result_count| URLs and the chain of redirects // leading to each of these URLs, filterd and sorted based on the |filter|. + // If |debug| is enabled, additional data will be computed and provided. void QueryFilteredURLs( scoped_refptr<QueryFilteredURLsRequest> request, int result_count, - const history::VisitFilter& filter); + const history::VisitFilter& filter, + bool debug); // QueryMostVisitedURLs without the request. void QueryMostVisitedURLsImpl(int result_count, diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc index 58e14e0..704b3ed 100644 --- a/chrome/browser/history/history_backend_unittest.cc +++ b/chrome/browser/history/history_backend_unittest.cc @@ -1323,7 +1323,7 @@ TEST_F(HistoryBackendTest, QueryFilteredURLs) { base::TimeDelta three_quarters_of_an_hour = base::TimeDelta::FromMinutes(45); filter.SetFilterTime(tested_time); filter.SetFilterWidth(three_quarters_of_an_hour); - backend_->QueryFilteredURLs(request1, 100, filter); + backend_->QueryFilteredURLs(request1, 100, filter, false); ASSERT_EQ(4U, get_filtered_list().size()); EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec()); @@ -1342,7 +1342,7 @@ TEST_F(HistoryBackendTest, QueryFilteredURLs) { request2); filter.SetFilterTime(tested_time + one_hour); filter.SetFilterWidth(one_hour); - backend_->QueryFilteredURLs(request2, 100, filter); + backend_->QueryFilteredURLs(request2, 100, filter, false); ASSERT_EQ(3U, get_filtered_list().size()); EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec()); @@ -1358,7 +1358,7 @@ TEST_F(HistoryBackendTest, QueryFilteredURLs) { request3); filter.SetFilterTime(tested_time - one_hour); filter.SetFilterWidth(one_hour); - backend_->QueryFilteredURLs(request3, 100, filter); + backend_->QueryFilteredURLs(request3, 100, filter, false); ASSERT_EQ(3U, get_filtered_list().size()); EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec()); @@ -1379,7 +1379,7 @@ TEST_F(HistoryBackendTest, QueryFilteredURLs) { request4); filter.SetFilterTime(tested_time); filter.SetDayOfTheWeekFilter(static_cast<int>(exploded_time.day_of_week)); - backend_->QueryFilteredURLs(request4, 100, filter); + backend_->QueryFilteredURLs(request4, 100, filter, false); ASSERT_EQ(2U, get_filtered_list().size()); EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec()); @@ -1395,11 +1395,26 @@ TEST_F(HistoryBackendTest, QueryFilteredURLs) { request5); filter.SetFilterTime(tested_time - base::TimeDelta::FromMinutes(40)); filter.SetFilterWidth(base::TimeDelta::FromMinutes(20)); - backend_->QueryFilteredURLs(request5, 100, filter); + backend_->QueryFilteredURLs(request5, 100, filter, false); ASSERT_EQ(1U, get_filtered_list().size()); EXPECT_EQ(std::string(yahoo_sports_soccer), get_filtered_list()[0].url.spec()); + + // Make sure we get debug data if we request it. + scoped_refptr<QueryFilteredURLsRequest> request6 = + new history::QueryFilteredURLsRequest( + base::Bind(&HistoryBackendTest::OnQueryFiltered, + base::Unretained(static_cast<HistoryBackendTest*>(this)))); + cancellable_request.MockScheduleOfRequest<QueryFilteredURLsRequest>( + request6); + filter.SetFilterTime(tested_time); + filter.SetFilterWidth(one_hour); + backend_->QueryFilteredURLs(request6, 100, filter, true); + + ASSERT_GE(get_filtered_list().size(), 1U); + EXPECT_EQ(std::string(google), get_filtered_list()[0].url.spec()); + EXPECT_EQ(4U, get_filtered_list()[0].extended_info.total_visits); } TEST_F(HistoryBackendTest, UpdateVisitDuration) { diff --git a/chrome/browser/history/history_types.cc b/chrome/browser/history/history_types.cc index c81cfe2..abe58cb 100644 --- a/chrome/browser/history/history_types.cc +++ b/chrome/browser/history/history_types.cc @@ -340,6 +340,14 @@ FilteredURL::FilteredURL(const PageUsageData& page_data) FilteredURL::~FilteredURL() {} +// FilteredURL::ExtendedInfo --------------------------------------------------- + +FilteredURL::ExtendedInfo::ExtendedInfo() + : total_visits(0), + visits(0), + duration_opened(0) { +} + // Images --------------------------------------------------------------------- Images::Images() {} diff --git a/chrome/browser/history/history_types.h b/chrome/browser/history/history_types.h index 49aa867..478e38f 100644 --- a/chrome/browser/history/history_types.h +++ b/chrome/browser/history/history_types.h @@ -597,6 +597,18 @@ struct MostVisitedURL { // Holds the per-URL information of the filterd url query. struct FilteredURL { + struct ExtendedInfo { + ExtendedInfo(); + // The absolute number of visits. + unsigned int total_visits; + // The number of visits, as seen by the Most Visited NTP pane. + unsigned int visits; + // The total number of seconds that the page was open. + int64 duration_opened; + // The time when the page was last visited. + base::Time last_visit_time; + }; + FilteredURL(); explicit FilteredURL(const PageUsageData& data); ~FilteredURL(); @@ -604,6 +616,7 @@ struct FilteredURL { GURL url; string16 title; double score; + ExtendedInfo extended_info; }; // Navigation ----------------------------------------------------------------- diff --git a/chrome/browser/resources/suggestions_internals/suggestions_internals.css b/chrome/browser/resources/suggestions_internals/suggestions_internals.css index 08bd27b..0e06d9e 100644 --- a/chrome/browser/resources/suggestions_internals/suggestions_internals.css +++ b/chrome/browser/resources/suggestions_internals/suggestions_internals.css @@ -22,3 +22,7 @@ p { .input-section { margin-bottom: 1em; } + +.has-screenshot { + background-color: rgb(146, 205, 0); +} diff --git a/chrome/browser/resources/suggestions_internals/suggestions_internals.js b/chrome/browser/resources/suggestions_internals/suggestions_internals.js index 6eef427..c4a0ed3 100644 --- a/chrome/browser/resources/suggestions_internals/suggestions_internals.js +++ b/chrome/browser/resources/suggestions_internals/suggestions_internals.js @@ -71,8 +71,16 @@ cr.define('suggestionsInternals', function() { var columns = []; list.forEach(function(entry) { for (var column in entry) { - if (columns.indexOf(column) < 0) + if (typeof(entry[column]) == 'object') { + // Expand one level deep + for (var sub_column in entry[column]) { + var path = column + '.' + sub_column; + if (columns.indexOf(path) < 0) + columns.push(path); + } + } else if (columns.indexOf(column) < 0) { columns.push(column); + } } }); @@ -114,10 +122,18 @@ cr.define('suggestionsInternals', function() { var row = document.createElement('tr'); columns.forEach(function(column_name) { var column = document.createElement('td'); + // Expand the path and find the data if it's there. + var path = column_name.split('.'); + var data = entry; + for (var i = 0; i < path.length; ++i) { + if (data && data.hasOwnProperty(path[i])) + data = data[path[i]]; + else + data = undefined; + } // Only add the column if the current suggestion has this property // (otherwise, leave the cell empty). - if (entry.hasOwnProperty(column_name)) { - var data = entry[column_name]; + if (data) { // If the text is a URL, make it an anchor element. if (/^https?:\/\/.+$/.test(data)) { var anchor = document.createElement('a'); @@ -132,7 +148,10 @@ cr.define('suggestionsInternals', function() { } else if (column_name == 'screenshot') { var thumbnailUrl = 'chrome://thumb/' + entry.url; var img = document.createElement('img'); - img.onload = function() { column.innerText = 'Y'; } + img.onload = function() { + column.innerText = 'Y'; + column.classList.add('has-screenshot'); + } img.onerror = function() { column.innerText = 'N'; } img.src = thumbnailUrl; } else if (column_name == 'favicon') { diff --git a/chrome/browser/ui/webui/ntp/suggestions_combiner.cc b/chrome/browser/ui/webui/ntp/suggestions_combiner.cc index 0e6137c..affa03a 100644 --- a/chrome/browser/ui/webui/ntp/suggestions_combiner.cc +++ b/chrome/browser/ui/webui/ntp/suggestions_combiner.cc @@ -26,14 +26,24 @@ SuggestionsCombiner::SuggestionsCombiner( : sources_fetching_count_(0), delegate_(delegate), suggestions_count_(kSuggestionsCount), - page_values_(new base::ListValue()) { + page_values_(new base::ListValue()), + debug_enabled_(false) { } SuggestionsCombiner::~SuggestionsCombiner() { } -base::ListValue* SuggestionsCombiner::GetPageValues() { - return page_values_.get(); +void SuggestionsCombiner::AddSource(SuggestionsSource* source) { + source->SetCombiner(this); + source->SetDebug(debug_enabled_); + sources_.push_back(source); +} + +void SuggestionsCombiner::EnableDebug(bool enable) { + debug_enabled_ = enable; + for (size_t i = 0; i < sources_.size(); ++i) { + sources_[i]->SetDebug(enable); + } } void SuggestionsCombiner::FetchItems(Profile* profile) { @@ -43,9 +53,8 @@ void SuggestionsCombiner::FetchItems(Profile* profile) { } } -void SuggestionsCombiner::AddSource(SuggestionsSource* source) { - source->SetCombiner(this); - sources_.push_back(source); +base::ListValue* SuggestionsCombiner::GetPageValues() { + return page_values_.get(); } void SuggestionsCombiner::OnItemsReady() { @@ -86,7 +95,7 @@ void SuggestionsCombiner::FillPageValues() { page_values_.reset(new base::ListValue()); - // Evaluate how many items to obtain from each sources. We use error diffusion + // Evaluate how many items to obtain from each source. We use error diffusion // to ensure that we get the total desired number of items. int error = 0; diff --git a/chrome/browser/ui/webui/ntp/suggestions_combiner.h b/chrome/browser/ui/webui/ntp/suggestions_combiner.h index f559430..5932321 100644 --- a/chrome/browser/ui/webui/ntp/suggestions_combiner.h +++ b/chrome/browser/ui/webui/ntp/suggestions_combiner.h @@ -39,6 +39,11 @@ class SuggestionsCombiner { // Add a new source. The SuggestionsCombiner takes ownership of |source|. void AddSource(SuggestionsSource* source); + // Enables or disables debug mode. If debug mode is enabled, the sources are + // expected to provide additional data, which could be displayed, for example, + // in the chrome://suggestions-internals/ page. + void EnableDebug(bool enable); + // Fetch a new set of items from the various suggestion sources. void FetchItems(Profile* profile); @@ -86,6 +91,10 @@ class SuggestionsCombiner { // Informations to send to the javascript side. scoped_ptr<base::ListValue> page_values_; + // Whether debug mode is enabled or not (debug mode provides more data in the + // results). + bool debug_enabled_; + DISALLOW_COPY_AND_ASSIGN(SuggestionsCombiner); }; diff --git a/chrome/browser/ui/webui/ntp/suggestions_combiner_unittest.cc b/chrome/browser/ui/webui/ntp/suggestions_combiner_unittest.cc index 01cea13..7b6f0bc 100644 --- a/chrome/browser/ui/webui/ntp/suggestions_combiner_unittest.cc +++ b/chrome/browser/ui/webui/ntp/suggestions_combiner_unittest.cc @@ -138,7 +138,8 @@ class SuggestionsSourceStub : public SuggestionsSource { : combiner_(NULL), weight_(weight), source_name_(source_name), - number_of_suggestions_(number_of_suggestions) { + number_of_suggestions_(number_of_suggestions), + debug_(false) { } virtual ~SuggestionsSourceStub() { STLDeleteElements(&items_); @@ -152,6 +153,9 @@ class SuggestionsSourceStub : public SuggestionsSource { private: // SuggestionsSource Override and implementation. + virtual void SetDebug(bool enable) OVERRIDE { + debug_ = enable; + } virtual int GetWeight() OVERRIDE { return weight_; } @@ -193,6 +197,7 @@ class SuggestionsSourceStub : public SuggestionsSource { int weight_; std::string source_name_; int number_of_suggestions_; + bool debug_; // Keep the results of the db query here. std::deque<base::DictionaryValue*> items_; diff --git a/chrome/browser/ui/webui/ntp/suggestions_source.h b/chrome/browser/ui/webui/ntp/suggestions_source.h index 067f0d7..10ef8d8 100644 --- a/chrome/browser/ui/webui/ntp/suggestions_source.h +++ b/chrome/browser/ui/webui/ntp/suggestions_source.h @@ -27,6 +27,10 @@ class SuggestionsSource { friend class SuggestionsCombiner; + // Enables or disables debug mode for the current source. The source is + // expected to provide additional data when debug mode is enabled. + virtual void SetDebug(bool enable) = 0; + // The source's weight indicates how many items from this source will be // selected by the combiner. If a source weight is x and the total weight of // all the sources is y, then the combiner will select x/y items from it. diff --git a/chrome/browser/ui/webui/ntp/suggestions_source_discovery.cc b/chrome/browser/ui/webui/ntp/suggestions_source_discovery.cc index 1ab266b..2aa5955 100644 --- a/chrome/browser/ui/webui/ntp/suggestions_source_discovery.cc +++ b/chrome/browser/ui/webui/ntp/suggestions_source_discovery.cc @@ -34,12 +34,17 @@ const int kSuggestionsDiscoveryWeight = 1; SuggestionsSourceDiscovery::SuggestionsSourceDiscovery( const std::string& extension_id) : combiner_(NULL), - extension_id_(extension_id) {} + extension_id_(extension_id), + debug_(false) {} SuggestionsSourceDiscovery::~SuggestionsSourceDiscovery() { STLDeleteElements(&items_); } +void SuggestionsSourceDiscovery::SetDebug(bool enable) { + debug_ = enable; +} + inline int SuggestionsSourceDiscovery::GetWeight() { return kSuggestionsDiscoveryWeight; } diff --git a/chrome/browser/ui/webui/ntp/suggestions_source_discovery.h b/chrome/browser/ui/webui/ntp/suggestions_source_discovery.h index a38ef34..788edd3 100644 --- a/chrome/browser/ui/webui/ntp/suggestions_source_discovery.h +++ b/chrome/browser/ui/webui/ntp/suggestions_source_discovery.h @@ -29,6 +29,7 @@ class SuggestionsSourceDiscovery : public SuggestionsSource { protected: // SuggestionsSource overrides: + virtual void SetDebug(bool enable) OVERRIDE; virtual int GetWeight() OVERRIDE; virtual int GetItemCount() OVERRIDE; virtual base::DictionaryValue* PopItem() OVERRIDE; @@ -45,6 +46,9 @@ class SuggestionsSourceDiscovery : public SuggestionsSource { // The extension associated with this source. std::string extension_id_; + // Whether the source should provide additional debug information or not. + bool debug_; + DISALLOW_COPY_AND_ASSIGN(SuggestionsSourceDiscovery); }; diff --git a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc b/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc index 8a8f5be..7e50c55 100644 --- a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc +++ b/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.cc @@ -26,13 +26,19 @@ const int kSuggestionsTopListWeight = 1; } // namespace -SuggestionsSourceTopSites::SuggestionsSourceTopSites() : combiner_(NULL) { +SuggestionsSourceTopSites::SuggestionsSourceTopSites() + : combiner_(NULL), + debug_(false) { } SuggestionsSourceTopSites::~SuggestionsSourceTopSites() { STLDeleteElements(&items_); } +void SuggestionsSourceTopSites::SetDebug(bool enable) { + debug_ = enable; +} + inline int SuggestionsSourceTopSites::GetWeight() { return kSuggestionsTopListWeight; } @@ -64,7 +70,7 @@ void SuggestionsSourceTopSites::FetchItems(Profile* profile) { time_filter.SetFilterWidth(GetFilterWidth()); time_filter.set_sorting_order(GetSortingOrder()); - history->QueryFilteredURLs(0, time_filter, &history_consumer_, + history->QueryFilteredURLs(0, time_filter, debug_, &history_consumer_, base::Bind(&SuggestionsSourceTopSites::OnSuggestionsURLsAvailable, base::Unretained(this))); } @@ -89,6 +95,26 @@ void SuggestionsSourceTopSites::OnSuggestionsURLsAvailable( suggested_url.title, suggested_url.url); page_value->SetDouble("score", suggested_url.score); + if (debug_) { + if (suggested_url.extended_info.total_visits) { + page_value->SetInteger("extended_info.total visits", + suggested_url.extended_info.total_visits); + } + if (suggested_url.extended_info.visits) { + page_value->SetInteger("extended_info.visits", + suggested_url.extended_info.visits); + } + if (suggested_url.extended_info.duration_opened) { + page_value->SetInteger("extended_info.duration opened", + suggested_url.extended_info.duration_opened); + } + if (!suggested_url.extended_info.last_visit_time.is_null()) { + base::TimeDelta deltaTime = + base::Time::Now() - suggested_url.extended_info.last_visit_time; + page_value->SetInteger("extended_info.seconds since last visit", + deltaTime.InSeconds()); + } + } items_.push_back(page_value); } diff --git a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h b/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h index d59ba5b..50f4470 100644 --- a/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h +++ b/chrome/browser/ui/webui/ntp/suggestions_source_top_sites.h @@ -30,6 +30,7 @@ class SuggestionsSourceTopSites : public SuggestionsSource { protected: // SuggestionsSource overrides: + virtual void SetDebug(bool enable) OVERRIDE; virtual int GetWeight() OVERRIDE; virtual int GetItemCount() OVERRIDE; virtual base::DictionaryValue* PopItem() OVERRIDE; @@ -57,6 +58,9 @@ class SuggestionsSourceTopSites : public SuggestionsSource { // Keep the results of the db query here. std::deque<base::DictionaryValue*> items_; + // Whether the source should provide additional debug information or not. + bool debug_; + CancelableRequestConsumer history_consumer_; DISALLOW_COPY_AND_ASSIGN(SuggestionsSourceTopSites); diff --git a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc b/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc index 6cdb757..dcb58e8 100644 --- a/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc +++ b/chrome/browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc @@ -33,6 +33,7 @@ void SuggestionsInternalsUIHandler::RegisterMessages() { // Setup the suggestions sources. suggestions_combiner_.reset(SuggestionsCombiner::Create(this, profile_)); suggestions_combiner_->SetSuggestionsCount(kSuggestionsCount); + suggestions_combiner_->EnableDebug(true); web_ui()->RegisterMessageCallback("getSuggestions", base::Bind(&SuggestionsInternalsUIHandler::HandleGetSuggestions, |