summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/autocomplete/history_contents_provider.cc72
-rw-r--r--chrome/browser/autocomplete/history_contents_provider.h40
-rw-r--r--chrome/browser/autocomplete/history_contents_provider_unittest.cc78
-rw-r--r--chrome/test/testing_profile.cc46
-rw-r--r--chrome/test/testing_profile.h7
5 files changed, 179 insertions, 64 deletions
diff --git a/chrome/browser/autocomplete/history_contents_provider.cc b/chrome/browser/autocomplete/history_contents_provider.cc
index f6ba682..2d03db9 100644
--- a/chrome/browser/autocomplete/history_contents_provider.cc
+++ b/chrome/browser/autocomplete/history_contents_provider.cc
@@ -4,8 +4,8 @@
#include "chrome/browser/autocomplete/history_contents_provider.h"
+#include "base/histogram.h"
#include "base/string_util.h"
-#include "chrome/browser/bookmark_bar_model.h"
#include "chrome/browser/history/query_parser.h"
#include "chrome/browser/profile.h"
#include "net/base/net_util.h"
@@ -43,9 +43,9 @@ void HistoryContentsProvider::Start(const AutocompleteInput& input,
matches_.clear();
if (input.text().empty() || (input.type() == AutocompleteInput::INVALID) ||
- // The history service must exist.
- (!history_service_ &&
- (!profile_ || !profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)))) {
+ // The history service or bookmark bar model must exist.
+ !(profile_->GetHistoryService(Profile::EXPLICIT_ACCESS) ||
+ profile_->GetBookmarkBarModel())) {
Stop();
return;
}
@@ -76,19 +76,32 @@ void HistoryContentsProvider::Start(const AutocompleteInput& input,
ConvertResults();
return;
} else if (!done_) {
- // We're still running the previous query. If we're allowed to keep running
- // it, do so, and when it finishes, its results will get marked up for this
- // new input. In synchronous_only mode, just cancel.
- if (synchronous_only)
- Stop();
+ // We're still running the previous query on the HistoryService. If we're
+ // allowed to keep running it, do so, and when it finishes, its results will
+ // get marked up for this new input. In synchronous_only mode, cancel the
+ // history query.
+ if (synchronous_only) {
+ done_ = true;
+ request_consumer_.CancelAllRequests();
+ }
+ ConvertResults();
return;
}
- // TODO(sky): re-enable providing suggestions from the user supplied title of
- // bookmarks.
+ if (results_.size() != 0) {
+ // Clear the results. We swap in an empty one as the easy way to clear it.
+ history::QueryResults empty_results;
+ results_.Swap(&empty_results);
+ }
+
+ // Querying bookmarks is synchronous, so we always do it.
+ QueryBookmarks(input);
+
+ // Convert the bookmark results.
+ ConvertResults();
if (!synchronous_only) {
- HistoryService* history = history_service_ ? history_service_ :
+ HistoryService* history =
profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
if (history) {
done_ = false;
@@ -111,17 +124,14 @@ void HistoryContentsProvider::Stop() {
history::QueryResults empty_results;
results_.Swap(&empty_results);
have_results_ = false;
-
- db_match_count_ = 0;
}
void HistoryContentsProvider::QueryComplete(HistoryService::Handle handle,
history::QueryResults* results) {
- results_.Swap(results);
+ results_.AppendResultsBySwapping(results, true);
have_results_ = true;
ConvertResults();
- db_match_count_ = static_cast<int>(results_.size());
done_ = true;
if (listener_)
listener_->OnProviderUpdate(!matches_.empty());
@@ -181,7 +191,8 @@ AutocompleteMatch HistoryContentsProvider::ResultToMatch(
ACMatchClassification(0, ACMatchClassification::URL));
match.description = result.title();
match.starred =
- (profile_ && profile_->GetBookmarkBarModel()->IsBookmarked(result.url()));
+ (profile_->GetBookmarkBarModel() &&
+ profile_->GetBookmarkBarModel()->IsBookmarked(result.url()));
ClassifyDescription(result, &match);
return match;
@@ -216,7 +227,8 @@ int HistoryContentsProvider::CalculateRelevance(
const history::URLResult& result) {
bool in_title = !!result.title_match_positions().size();
bool is_starred =
- (profile_ && profile_->GetBookmarkBarModel()->IsBookmarked(result.url()));
+ (profile_->GetBookmarkBarModel() &&
+ profile_->GetBookmarkBarModel()->IsBookmarked(result.url()));
switch (input_type_) {
case AutocompleteInput::UNKNOWN:
@@ -245,3 +257,27 @@ int HistoryContentsProvider::CalculateRelevance(
}
}
+void HistoryContentsProvider::QueryBookmarks(const AutocompleteInput& input) {
+ BookmarkBarModel* bookmark_model = profile_->GetBookmarkBarModel();
+ if (!bookmark_model)
+ return;
+
+ DCHECK(results_.size() == 0); // When we get here the results should be
+ // empty.
+
+ TimeTicks start_time = TimeTicks::Now();
+ std::vector<BookmarkBarModel::TitleMatch> matches;
+ bookmark_model->GetBookmarksMatchingText(input.text(), kMaxMatchCount,
+ &matches);
+ for (size_t i = 0; i < matches.size(); ++i)
+ AddBookmarkTitleMatchToResults(matches[i]);
+ UMA_HISTOGRAM_TIMES(L"Omnibox.QueryBookmarksTime",
+ TimeTicks::Now() - start_time);
+}
+
+void HistoryContentsProvider::AddBookmarkTitleMatchToResults(
+ const BookmarkBarModel::TitleMatch& match) {
+ history::URLResult url_result(match.node->GetURL(), match.match_positions);
+ url_result.set_title(match.node->GetTitle());
+ results_.AppendURLBySwapping(&url_result);
+}
diff --git a/chrome/browser/autocomplete/history_contents_provider.h b/chrome/browser/autocomplete/history_contents_provider.h
index 85665bb..b2451ee 100644
--- a/chrome/browser/autocomplete/history_contents_provider.h
+++ b/chrome/browser/autocomplete/history_contents_provider.h
@@ -6,29 +6,24 @@
#define CHROME_BROWSER_AUTOCOMPLETE_HISTORY_CONTENTS_PROVIDER_H__
#include "chrome/browser/autocomplete/autocomplete.h"
+#include "chrome/browser/bookmark_bar_model.h"
#include "chrome/browser/history/history.h"
// HistoryContentsProvider is an AutocompleteProvider that provides results from
-// the contents (body and/or title) of previously visited pages. Results are
-// obtained asynchronously from the history service.
+// the contents (body and/or title) of previously visited pages.
+// HistoryContentsProvider gets results from two sources:
+// . HistoryService: this provides results for matches in the body/title of
+// previously viewed pages. This is asynchronous.
+// . BookmarkBarModel: provides results for matches in the titles of bookmarks.
+// This is synchronous.
class HistoryContentsProvider : public AutocompleteProvider {
public:
HistoryContentsProvider(ACProviderListener* listener, Profile* profile)
: AutocompleteProvider(listener, profile, "HistoryContents"),
- history_service_(NULL),
have_results_(false) {
DCHECK(profile);
}
-#ifdef UNIT_TEST
- HistoryContentsProvider(ACProviderListener* listener,
- HistoryService* history_service)
- : AutocompleteProvider(listener, NULL, "HistoryContents"),
- history_service_(history_service),
- have_results_(false) {
- }
-#endif
-
// As necessary asks the history service for the relevant results. When
// done SetResults is invoked.
virtual void Start(const AutocompleteInput& input,
@@ -39,8 +34,8 @@ class HistoryContentsProvider : public AutocompleteProvider {
// Returns the total number of matches available in the database, up to
// kMaxMatchCount, whichever is smaller.
- // Return value is only valid if done() returns true.
- size_t db_match_count() const { return db_match_count_; }
+ // Return value is incomplete if done() returns false.
+ size_t db_match_count() const { return results_.size(); }
// The maximum match count we'll report. If the db_match_count is greater
// than this, it will be clamped to this result.
@@ -67,11 +62,16 @@ class HistoryContentsProvider : public AutocompleteProvider {
// chart in autocomplete.h for the list of values this returns.
int CalculateRelevance(const history::URLResult& result);
- CancelableRequestConsumerT<int, 0> request_consumer_;
+ // Queries the bookmarks for any bookmarks whose title matches input. All
+ // matches are added directly to results_.
+ void QueryBookmarks(const AutocompleteInput& input);
- // This is only non-null for testing, otherwise the HistoryService from the
- // Profile is used.
- HistoryService* history_service_;
+ // Converts a BookmarkBarModel::TitleMatch to a QueryResult and adds it
+ // to results_.
+ void AddBookmarkTitleMatchToResults(
+ const BookmarkBarModel::TitleMatch& match);
+
+ CancelableRequestConsumerT<int, 0> request_consumer_;
// The number of times we're returned each different type of result. These are
// used by CalculateRelevance. Initialized in Start.
@@ -93,11 +93,7 @@ class HistoryContentsProvider : public AutocompleteProvider {
// Current query string.
std::wstring query_;
- // Total number of matches available in the database.
- int db_match_count_;
-
DISALLOW_EVIL_CONSTRUCTORS(HistoryContentsProvider);
};
#endif // CHROME_BROWSER_AUTOCOMPLETE_HISTORY_CONTENTS_PROVIDER_H__
-
diff --git a/chrome/browser/autocomplete/history_contents_provider_unittest.cc b/chrome/browser/autocomplete/history_contents_provider_unittest.cc
index 2e1a646..5796f4d 100644
--- a/chrome/browser/autocomplete/history_contents_provider_unittest.cc
+++ b/chrome/browser/autocomplete/history_contents_provider_unittest.cc
@@ -8,6 +8,7 @@
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/history_contents_provider.h"
#include "chrome/browser/history/history.h"
+#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -45,16 +46,18 @@ class HistoryContentsProviderTest : public testing::Test,
const ACMatches& matches() const { return provider_->matches(); }
+ TestingProfile* profile() const { return profile_.get(); }
+
+ HistoryContentsProvider* provider() const { return provider_.get(); }
+
private:
// testing::Test
virtual void SetUp() {
- PathService::Get(base::DIR_TEMP, &history_dir_);
- file_util::AppendToPath(&history_dir_, L"HistoryContentProviderTest");
- file_util::Delete(history_dir_, true); // Normally won't exist.
- file_util::CreateDirectoryW(history_dir_);
+ profile_.reset(new TestingProfile());
+ profile_->CreateHistoryService(false);
- history_service_ = new HistoryService;
- history_service_->Init(history_dir_, NULL);
+ HistoryService* history_service =
+ profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
// Populate history.
for (int i = 0; i < arraysize(test_entries); i++) {
@@ -67,28 +70,18 @@ class HistoryContentsProviderTest : public testing::Test,
// is "right now" or it will nondeterministically appear in the results.
Time t = Time::Now() - TimeDelta::FromDays(arraysize(test_entries) + i);
- history_service_->AddPage(url, t, id_scope, i, GURL(),
+ history_service->AddPage(url, t, id_scope, i, GURL(),
PageTransition::LINK, HistoryService::RedirectList());
- history_service_->SetPageTitle(url, test_entries[i].title);
- history_service_->SetPageContents(url, test_entries[i].body);
+ history_service->SetPageTitle(url, test_entries[i].title);
+ history_service->SetPageContents(url, test_entries[i].body);
}
- provider_ = new HistoryContentsProvider(this, history_service_);
+ provider_ = new HistoryContentsProvider(this, profile_.get());
}
virtual void TearDown() {
- history_service_->SetOnBackendDestroyTask(new MessageLoop::QuitTask);
- history_service_->Cleanup();
provider_ = NULL;
- history_service_ = NULL;
-
- // Wait for history thread to complete (the QuitTask will cause it to exit
- // on destruction). Note: if this never terminates, somebody is probably
- // leaking a reference to the history backend, so it never calls our
- // destroy task.
- MessageLoop::current()->Run();
-
- file_util::Delete(history_dir_, true);
+ profile_.reset(NULL);
}
// ACProviderListener
@@ -98,11 +91,11 @@ class HistoryContentsProviderTest : public testing::Test,
}
MessageLoopForUI message_loop_;
-
+
std::wstring history_dir_;
+ scoped_ptr<TestingProfile> profile_;
scoped_refptr<HistoryContentsProvider> provider_;
- scoped_refptr<HistoryService> history_service_;
};
} // namespace
@@ -154,3 +147,42 @@ TEST_F(HistoryContentsProviderTest, MinimalChanges) {
const ACMatches& m3 = matches();
EXPECT_EQ(2, m3.size());
}
+
+// Tests that the BookmarkBarModel is queried correctly.
+TEST_F(HistoryContentsProviderTest, Bookmarks) {
+ profile()->CreateBookmarkBarModel(false);
+ profile()->BlockUntilBookmarkModelLoaded();
+
+ // Add a bookmark.
+ GURL bookmark_url("http://www.google.com/4");
+ profile()->GetBookmarkBarModel()->SetURLStarred(bookmark_url, L"bar", true);
+
+ AutocompleteInput input(L"bar", std::wstring(), true);
+
+ // Ask for synchronous. This should only get the bookmark.
+ RunQuery(input, false, true);
+ const ACMatches& m1 = matches();
+ ASSERT_EQ(1, m1.size());
+ EXPECT_EQ(bookmark_url.spec(), WideToUTF8(m1[0].destination_url));
+ EXPECT_EQ(L"bar", m1[0].description);
+ EXPECT_TRUE(m1[0].starred);
+
+ // Ask for async. We should get the bookmark immediately.
+ provider()->Start(input, false, false);
+ const ACMatches& m2 = matches();
+ ASSERT_EQ(1, m2.size());
+ EXPECT_EQ(bookmark_url.spec(), WideToUTF8(m2[0].destination_url));
+
+ // Run the message loop (needed for async history results).
+ MessageLoop::current()->Run();
+
+ // We should two urls now, bookmark_url and http://www.google.com/3.
+ const ACMatches& m3 = matches();
+ ASSERT_EQ(2, m3.size());
+ if (bookmark_url.spec() == WideToUTF8(m3[0].destination_url)) {
+ EXPECT_EQ(L"http://www.google.com/3", m3[1].destination_url);
+ } else {
+ EXPECT_EQ(bookmark_url.spec(), WideToUTF8(m3[1].destination_url));
+ EXPECT_EQ(L"http://www.google.com/3", m3[0].destination_url);
+ }
+}
diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc
index c91c372..ac7021d 100644
--- a/chrome/test/testing_profile.cc
+++ b/chrome/test/testing_profile.cc
@@ -7,6 +7,40 @@
#include "chrome/browser/history/history_backend.h"
#include "chrome/common/chrome_constants.h"
+namespace {
+
+// BookmarkLoadObserver is used when blocking until the BookmarkBarModel
+// finishes loading. As soon as the BookmarkBarModel finishes loading the
+// message loop is quit.
+class BookmarkLoadObserver : public BookmarkBarModelObserver {
+ public:
+ BookmarkLoadObserver() {}
+ virtual void Loaded(BookmarkBarModel* model) {
+ MessageLoop::current()->Quit();
+ }
+
+ virtual void BookmarkNodeMoved(BookmarkBarModel* model,
+ BookmarkBarNode* old_parent,
+ int old_index,
+ BookmarkBarNode* new_parent,
+ int new_index) {}
+ virtual void BookmarkNodeAdded(BookmarkBarModel* model,
+ BookmarkBarNode* parent,
+ int index) {}
+ virtual void BookmarkNodeRemoved(BookmarkBarModel* model,
+ BookmarkBarNode* parent,
+ int index) {}
+ virtual void BookmarkNodeChanged(BookmarkBarModel* model,
+ BookmarkBarNode* node) {}
+ virtual void BookmarkNodeFavIconLoaded(BookmarkBarModel* model,
+ BookmarkBarNode* node) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BookmarkLoadObserver);
+};
+
+} // namespace
+
TestingProfile::TestingProfile()
: start_time_(Time::Now()), has_history_service_(false) {
PathService::Get(base::DIR_TEMP, &path_);
@@ -75,7 +109,17 @@ void TestingProfile::CreateBookmarkBarModel(bool delete_file) {
bookmark_bar_model_->Load();
}
+void TestingProfile::BlockUntilBookmarkModelLoaded() {
+ DCHECK(bookmark_bar_model_.get());
+ if (bookmark_bar_model_->IsLoaded())
+ return;
+ BookmarkLoadObserver observer;
+ bookmark_bar_model_->AddObserver(&observer);
+ MessageLoop::current()->Run();
+ bookmark_bar_model_->RemoveObserver(&observer);
+ DCHECK(bookmark_bar_model_->IsLoaded());
+}
+
void TestingProfile::CreateTemplateURLModel() {
template_url_model_.reset(new TemplateURLModel(this));
}
-
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index 3d8e04c..4ff9dbb 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -31,8 +31,15 @@ class TestingProfile : public Profile {
// the model is created. As TestingProfile deletes the directory containing
// the files used by HistoryService, the boolean only matters if you're
// recreating the BookmarkBarModel.
+ //
+ // NOTE: this does not block until the bookmarks are loaded. For that use
+ // BlockUntilBookmarkModelLoaded.
void CreateBookmarkBarModel(bool delete_file);
+ // Blocks until the BookmarkBarModel finishes loaded. This is NOT invoked
+ // from CreateBookmarkBarModel.
+ void BlockUntilBookmarkModelLoaded();
+
// Creates a TemplateURLModel. If not invoked the TemplateURLModel is NULL.
void CreateTemplateURLModel();