summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorsky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-21 15:20:33 +0000
committersky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-21 15:20:33 +0000
commitf25387b62a3cccde48622d0b7fca57cd6fb16ab7 (patch)
tree06ac2c1972d6608fb65979c3a279a6d214fecc6c /chrome/browser
parentbcc682fc4f5050ac911635ab649fbd30002fc2b4 (diff)
downloadchromium_src-f25387b62a3cccde48622d0b7fca57cd6fb16ab7.zip
chromium_src-f25387b62a3cccde48622d0b7fca57cd6fb16ab7.tar.gz
chromium_src-f25387b62a3cccde48622d0b7fca57cd6fb16ab7.tar.bz2
Moves bookmarks out of history into its own file (JSON).
Interesting points: . Migration was a bit atypical. Here is the approach I took: . If the URL db contains bookmarks it writes the bookmarks to a temporary file. . When the bookmark bar model is loaded it assumes bookmarks are stored in a file. If the bookmarks file doesn't exist it then attempts to load from history, after waiting for history to finish processing tasks. . I've broken having the omnibox query for starred only. This patch was already too ginormous for me to contemplate this too. I'll return to it after I land this. . Similarly the history page isn't searching for starred titles now. As we discussed with Glen, that is probably fine for now. . I've converted NOTIFY_STARRED_FAVICON_CHANGED to NOTIFY_FAVICON_CHANGED and it is notified ANY time a favicon changes. I'm mildly concerned about the extra notifications, but without having history know about starred it's the best I can do for now. . Autocomplete (specifically URLDatabase::AutocompleteForPrefix) previously sorted by starred. It can no longer do this. I don't think I can get this functionality back:( Luckily it only mattered if you had a starred and non-starred URL with the same type count that matched a query. Probably pretty rare. What's left: . Fix up HistoryContentsProvider to query for starred entries titles. . Clean up the delete all case. I basically just made it compile; it can be greatly simplified. . Rename BookmarkBarModel to BookmarksModel. BUG=1256202 TEST=this is a huge change to bookmarks. Thanfully it's pretty well covered by tests, none-the-less make sure you exercise bookmarks pretty heavily to make sure nothing is busted. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1153 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/autocomplete/history_contents_provider.cc11
-rw-r--r--chrome/browser/autocomplete/history_url_provider.cc8
-rw-r--r--chrome/browser/autocomplete/history_url_provider_unittest.cc41
-rw-r--r--chrome/browser/autocomplete/search_provider.cc5
-rw-r--r--chrome/browser/bookmark_bar_model.cc513
-rw-r--r--chrome/browser/bookmark_bar_model.h174
-rw-r--r--chrome/browser/bookmark_bar_model_unittest.cc293
-rw-r--r--chrome/browser/bookmark_codec.cc63
-rw-r--r--chrome/browser/bookmark_codec.h15
-rw-r--r--chrome/browser/bookmark_drag_data.cc18
-rw-r--r--chrome/browser/bookmark_drag_data.h10
-rw-r--r--chrome/browser/bookmark_storage.cc172
-rw-r--r--chrome/browser/bookmark_storage.h63
-rw-r--r--chrome/browser/browser.vcproj16
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.cc56
-rw-r--r--chrome/browser/dom_ui/new_tab_ui.h34
-rw-r--r--chrome/browser/history/archived_database.cc46
-rw-r--r--chrome/browser/history/archived_database.h9
-rw-r--r--chrome/browser/history/expire_history_backend.cc25
-rw-r--r--chrome/browser/history/expire_history_backend.h7
-rw-r--r--chrome/browser/history/expire_history_backend_unittest.cc131
-rw-r--r--chrome/browser/history/history.cc56
-rw-r--r--chrome/browser/history/history.h75
-rw-r--r--chrome/browser/history/history_backend.cc264
-rw-r--r--chrome/browser/history/history_backend.h31
-rw-r--r--chrome/browser/history/history_backend_unittest.cc34
-rw-r--r--chrome/browser/history/history_database.cc24
-rw-r--r--chrome/browser/history/history_database.h11
-rw-r--r--chrome/browser/history/history_marshaling.h16
-rw-r--r--chrome/browser/history/history_notifications.h12
-rw-r--r--chrome/browser/history/history_querying_unittest.cc33
-rw-r--r--chrome/browser/history/history_types.cc3
-rw-r--r--chrome/browser/history/history_types.h45
-rw-r--r--chrome/browser/history/history_unittest.cc73
-rw-r--r--chrome/browser/history/in_memory_history_backend.cc22
-rw-r--r--chrome/browser/history/in_memory_history_backend.h3
-rw-r--r--chrome/browser/history/starred_url_database.cc469
-rw-r--r--chrome/browser/history/starred_url_database.h151
-rw-r--r--chrome/browser/history/starred_url_database_unittest.cc392
-rw-r--r--chrome/browser/history/text_database.h2
-rw-r--r--chrome/browser/history/text_database_manager.h2
-rw-r--r--chrome/browser/history/url_database.cc68
-rw-r--r--chrome/browser/history/url_database.h9
-rw-r--r--chrome/browser/history/url_database_unittest.cc3
-rw-r--r--chrome/browser/history_model.cc18
-rw-r--r--chrome/browser/history_model.h12
-rw-r--r--chrome/browser/views/bookmark_editor_view.cc15
-rw-r--r--chrome/browser/views/bookmark_editor_view.h5
48 files changed, 1172 insertions, 2386 deletions
diff --git a/chrome/browser/autocomplete/history_contents_provider.cc b/chrome/browser/autocomplete/history_contents_provider.cc
index c68b17c..564f832 100644
--- a/chrome/browser/autocomplete/history_contents_provider.cc
+++ b/chrome/browser/autocomplete/history_contents_provider.cc
@@ -30,6 +30,7 @@
#include "chrome/browser/autocomplete/history_contents_provider.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"
@@ -108,6 +109,7 @@ void HistoryContentsProvider::Start(const AutocompleteInput& input,
return;
}
+ // TODO(sky): this needs to query BookmarkBarModel for starred entries.
if (!synchronous_only) {
HistoryService* history = history_service_ ? history_service_ :
profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
@@ -201,7 +203,8 @@ AutocompleteMatch HistoryContentsProvider::ResultToMatch(
match.contents_class.push_back(
ACMatchClassification(0, ACMatchClassification::URL));
match.description = result.title();
- match.starred = result.starred();
+ match.starred =
+ (profile_ && profile_->GetBookmarkBarModel()->IsBookmarked(result.url()));
ClassifyDescription(result, &match);
return match;
@@ -235,11 +238,13 @@ void HistoryContentsProvider::ClassifyDescription(
int HistoryContentsProvider::CalculateRelevance(
const history::URLResult& result) {
bool in_title = !!result.title_match_positions().size();
+ bool is_starred =
+ (profile_ && profile_->GetBookmarkBarModel()->IsBookmarked(result.url()));
switch (input_type_) {
case AutocompleteInput::UNKNOWN:
case AutocompleteInput::REQUESTED_URL:
- if (result.starred()) {
+ if (is_starred) {
return in_title ? 1000 + star_title_count_++ :
550 + star_contents_count_++;
} else {
@@ -249,7 +254,7 @@ int HistoryContentsProvider::CalculateRelevance(
case AutocompleteInput::QUERY:
case AutocompleteInput::FORCED_QUERY:
- if (result.starred()) {
+ if (is_starred) {
return in_title ? 1200 + star_title_count_++ :
750 + star_contents_count_++;
} else {
diff --git a/chrome/browser/autocomplete/history_url_provider.cc b/chrome/browser/autocomplete/history_url_provider.cc
index 1db8c00..d0ee441 100644
--- a/chrome/browser/autocomplete/history_url_provider.cc
+++ b/chrome/browser/autocomplete/history_url_provider.cc
@@ -48,6 +48,8 @@
#include "googleurl/src/url_util.h"
#include "net/base/net_util.h"
+// TODO(sky): this needs to check and update starred state.
+
HistoryURLProviderParams::HistoryURLProviderParams(
const AutocompleteInput& input,
bool trim_http,
@@ -315,7 +317,6 @@ bool HistoryURLProvider::FixupExactSuggestion(history::URLDatabase* db,
return false;
} else {
// We have data for this match, use it.
- match.starred = info.starred();
match.deletable = true;
match.description = info.title();
AutocompleteMatch::ClassifyMatchInString(params->input.text(),
@@ -439,10 +440,6 @@ bool HistoryURLProvider::CompareHistoryMatch(const HistoryMatch& a,
if (a.url_info.typed_count() != b.url_info.typed_count())
return a.url_info.typed_count() > b.url_info.typed_count();
- // Starred pages are better than unstarred pages.
- if (a.url_info.starred() != b.url_info.starred())
- return a.url_info.starred();
-
// For URLs that have each been typed once, a host (alone) is better than a
// page inside.
if (a.url_info.typed_count() == 1) {
@@ -851,6 +848,5 @@ AutocompleteMatch HistoryURLProvider::HistoryMatchToACMatch(
ACMatchClassification::NONE,
&match.description_class);
- match.starred = history_match.url_info.starred();
return match;
}
diff --git a/chrome/browser/autocomplete/history_url_provider_unittest.cc b/chrome/browser/autocomplete/history_url_provider_unittest.cc
index 44486e7..9e70a38 100644
--- a/chrome/browser/autocomplete/history_url_provider_unittest.cc
+++ b/chrome/browser/autocomplete/history_url_provider_unittest.cc
@@ -31,7 +31,9 @@
#include "base/message_loop.h"
#include "base/path_service.h"
#include "chrome/browser/autocomplete/history_url_provider.h"
+#include "chrome/browser/bookmark_bar_model.h"
#include "chrome/browser/history/history.h"
+#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
struct TestURLInfo {
@@ -122,10 +124,10 @@ class HistoryURLProviderTest : public testing::Test,
int num_results);
ACMatches matches_;
- scoped_refptr<HistoryService> history_service_;
+ scoped_ptr<TestingProfile> profile_;
+ HistoryService* history_service_;
private:
- std::wstring history_dir_;
scoped_refptr<HistoryURLProvider> autocomplete_;
};
@@ -135,32 +137,18 @@ void HistoryURLProviderTest::OnProviderUpdate(bool updated_matches) {
}
void HistoryURLProviderTest::SetUp() {
- PathService::Get(base::DIR_TEMP, &history_dir_);
- file_util::AppendToPath(&history_dir_, L"HistoryURLProviderTest");
- file_util::Delete(history_dir_, true); // Normally won't exist.
- file_util::CreateDirectoryW(history_dir_);
+ profile_.reset(new TestingProfile());
+ profile_->CreateBookmarkBarModel();
+ profile_->CreateHistoryService(true);
+ history_service_ = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- history_service_ = new HistoryService;
- history_service_->Init(history_dir_);
-
- autocomplete_ = new HistoryURLProvider(this, history_service_);
+ autocomplete_ = new HistoryURLProvider(this, profile_.get());
FillData();
}
void HistoryURLProviderTest::TearDown() {
- history_service_->SetOnBackendDestroyTask(new MessageLoop::QuitTask);
- history_service_->Cleanup();
autocomplete_ = 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);
}
void HistoryURLProviderTest::FillData() {
@@ -180,11 +168,8 @@ void HistoryURLProviderTest::FillData() {
cur.visit_count, cur.typed_count,
visit_time, false);
if (cur.starred) {
- history::StarredEntry star_entry;
- star_entry.type = history::StarredEntry::URL;
- star_entry.parent_group_id = HistoryService::kBookmarkBarID;
- star_entry.url = current_url;
- history_service_->CreateStarredEntry(star_entry, NULL, NULL);
+ profile_->GetBookmarkBarModel()->SetURLStarred(
+ current_url, std::wstring(), true);
}
}
}
@@ -288,7 +273,9 @@ TEST_F(HistoryURLProviderTest, PromoteShorterURLs) {
arraysize(short_4));
}
-TEST_F(HistoryURLProviderTest, Starred) {
+// Bookmarks have been moved out of the history db, resulting in this no longer
+// working. See TODO in URLDatabase::AutocompleteForPrefix.
+TEST_F(HistoryURLProviderTest, DISABLED_Starred) {
// Test that starred pages sort properly.
const std::wstring star_1[] = {
L"http://startest/",
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index fbc24b5..6f66694 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -31,6 +31,7 @@
#include "base/message_loop.h"
#include "base/string_util.h"
+#include "chrome/browser/bookmark_bar_model.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/google_util.h"
#include "chrome/browser/profile.h"
@@ -238,7 +239,9 @@ void SearchProvider::OnQueryURLComplete(HistoryService::Handle handle,
bool success,
const history::URLRow* url_row,
history::VisitVector* unused) {
- bool is_starred = success ? url_row->starred() : false;
+ bool is_starred =
+ (success && profile_ &&
+ profile_->GetBookmarkBarModel()->IsBookmarked(url_row->url()));
star_requests_pending_ = false;
// We can't just use star_request_consumer_.HasPendingRequests() here;
// see comment in ConvertResultsToAutocompleteMatches().
diff --git a/chrome/browser/bookmark_bar_model.cc b/chrome/browser/bookmark_bar_model.cc
index c6c9312..e9a0511 100644
--- a/chrome/browser/bookmark_bar_model.cc
+++ b/chrome/browser/bookmark_bar_model.cc
@@ -30,11 +30,36 @@
#include "chrome/browser/bookmark_bar_model.h"
#include "base/gfx/png_decoder.h"
+#include "chrome/browser/history/query_parser.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/bookmark_storage.h"
+#include "chrome/common/scoped_vector.h"
+
#include "generated_resources.h"
+namespace {
+
+// Functions used for sorting.
+bool MoreRecentlyModified(BookmarkBarNode* n1, BookmarkBarNode* n2) {
+ return n1->date_group_modified() > n2->date_group_modified();
+}
+
+bool MoreRecentlyAdded(BookmarkBarNode* n1, BookmarkBarNode* n2) {
+ return n1->date_added() > n2->date_added();
+}
+
+} // namespace
+
// BookmarkBarNode ------------------------------------------------------------
+namespace {
+
+// ID for BookmarkBarNodes.
+// Various places assume an invalid id if == 0, for that reason we start with 1.
+int next_id_ = 1;
+
+}
+
const SkBitmap& BookmarkBarNode::GetFavIcon() {
if (!loaded_favicon_) {
loaded_favicon_ = true;
@@ -43,95 +68,74 @@ const SkBitmap& BookmarkBarNode::GetFavIcon() {
return favicon_;
}
-BookmarkBarNode::BookmarkBarNode(BookmarkBarModel* model)
+BookmarkBarNode::BookmarkBarNode(BookmarkBarModel* model, const GURL& url)
: model_(model),
- group_id_(0),
- star_id_(0),
+ id_(next_id_++),
loaded_favicon_(false),
favicon_load_handle_(0),
- type_(history::StarredEntry::BOOKMARK_BAR),
+ url_(url),
+ type_(!url.is_empty() ? history::StarredEntry::URL :
+ history::StarredEntry::BOOKMARK_BAR),
date_added_(Time::Now()) {
- DCHECK(model_);
}
void BookmarkBarNode::Reset(const history::StarredEntry& entry) {
- // We should either have no id, or the id of the new entry should match
- // this.
- DCHECK(!star_id_ || star_id_ == entry.id);
- star_id_ = entry.id;
- group_id_ = entry.group_id;
- url_ = entry.url;
+ DCHECK(entry.type != history::StarredEntry::URL ||
+ entry.url == url_);
+
favicon_ = SkBitmap();
- loaded_favicon_ = false;
- favicon_load_handle_ = 0;
type_ = entry.type;
date_added_ = entry.date_added;
date_group_modified_ = entry.date_group_modified;
SetTitle(entry.title);
}
-void BookmarkBarNode::SetURL(const GURL& url) {
- DCHECK(favicon_load_handle_ == 0);
- loaded_favicon_ = false;
- favicon_load_handle_ = 0;
- url_ = url;
- favicon_ .reset();
-}
-
-history::StarredEntry BookmarkBarNode::GetEntry() {
- history::StarredEntry entry;
- entry.id = GetStarID();
- entry.group_id = group_id_;
- entry.url = GetURL();
- entry.title = GetTitle();
- entry.type = type_;
- entry.date_added = date_added_;
- entry.date_group_modified = date_group_modified_;
- // Only set the parent and visual order if we have a valid parent (the root
- // node is not in the db and has a group_id of 0).
- if (GetParent() && GetParent()->group_id_) {
- entry.visual_order = GetParent()->IndexOfChild(this);
- entry.parent_group_id = GetParent()->GetGroupID();
- }
- return entry;
-}
-
// BookmarkBarModel -----------------------------------------------------------
BookmarkBarModel::BookmarkBarModel(Profile* profile)
: profile_(profile),
loaded_(false),
#pragma warning(suppress: 4355) // Okay to pass "this" here.
- root_(this),
- // See declaration for description.
- next_group_id_(HistoryService::kBookmarkBarID + 1),
+ root_(this, GURL()),
bookmark_bar_node_(NULL),
other_node_(NULL) {
- // Notifications we want.
- if (profile_)
- NotificationService::current()->AddObserver(
- this, NOTIFY_STARRED_FAVICON_CHANGED, Source<Profile>(profile_));
-
- if (!profile || !profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)) {
- // Profile/HistoryService is NULL during testing.
- CreateBookmarkBarNode();
- CreateOtherBookmarksNode();
- AddRootChildren(NULL);
+ // Create the bookmark bar and other bookmarks folders. These always exist.
+ CreateBookmarkBarNode();
+ CreateOtherBookmarksNode();
+
+ // And add them to the root.
+ //
+ // WARNING: order is important here, various places assume bookmark bar then
+ // other node.
+ root_.Add(0, bookmark_bar_node_);
+ root_.Add(1, other_node_);
+
+ if (!profile_) {
+ // Profile is null during testing.
loaded_ = true;
return;
}
- // Request the entries on the bookmark bar.
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)->
- GetAllStarredEntries(&load_consumer_,
- NewCallback(this,
- &BookmarkBarModel::OnGotStarredEntries));
+ // Listen for changes to starred icons so that we can update the favicon of
+ // the node appropriately.
+ NotificationService::current()->AddObserver(
+ this, NOTIFY_FAVICON_CHANGED, Source<Profile>(profile_));
+
+ // Load the bookmarks. BookmarkStorage notifies us when done.
+ store_ = new BookmarkStorage(profile_, this);
+ store_->LoadBookmarks(false);
}
BookmarkBarModel::~BookmarkBarModel() {
if (profile_) {
NotificationService::current()->RemoveObserver(
- this, NOTIFY_STARRED_FAVICON_CHANGED, Source<Profile>(profile_));
+ this, NOTIFY_FAVICON_CHANGED, Source<Profile>(profile_));
+ }
+
+ if (store_) {
+ // The store maintains a reference back to us. We need to tell it we're gone
+ // so that it doesn't try and invoke a method back on us again.
+ store_->BookmarkModelDeleted();
}
}
@@ -160,38 +164,50 @@ std::vector<BookmarkBarNode*> BookmarkBarModel::GetMostRecentlyModifiedGroups(
return nodes;
}
-void BookmarkBarModel::Remove(BookmarkBarNode* parent, int index) {
-#ifndef NDEBUG
- CheckIndex(parent, index, false);
-#endif
- if (parent != &root_) {
- RemoveAndDeleteNode(parent->GetChild(index));
- } else {
- NOTREACHED(); // Can't remove from the root.
+void BookmarkBarModel::GetMostRecentlyAddedEntries(
+ size_t count,
+ std::vector<BookmarkBarNode*>* nodes) {
+ for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin();
+ i != nodes_ordered_by_url_set_.end(); ++i) {
+ std::vector<BookmarkBarNode*>::iterator insert_position =
+ std::upper_bound(nodes->begin(), nodes->end(), *i, &MoreRecentlyAdded);
+ if (nodes->size() < count || insert_position != nodes->end()) {
+ nodes->insert(insert_position, *i);
+ while (nodes->size() > count)
+ nodes->pop_back();
+ }
}
}
-void BookmarkBarModel::RemoveFromBookmarkBar(BookmarkBarNode* node) {
- if (!node->HasAncestor(bookmark_bar_node_))
+void BookmarkBarModel::GetBookmarksMatchingText(
+ const std::wstring& text,
+ std::vector<BookmarkBarNode*>* nodes) {
+ QueryParser parser;
+ ScopedVector<QueryNode> query_nodes;
+ parser.ParseQuery(text, &query_nodes.get());
+ if (query_nodes.empty())
return;
- if (node != &root_ && node != bookmark_bar_node_ && node != other_node_) {
- Move(node, other_node_, other_node_->GetChildCount());
- } else {
- NOTREACHED(); // Can't move the root, bookmark bar or other nodes.
+ for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin();
+ i != nodes_ordered_by_url_set_.end(); ++i) {
+ if (parser.DoesQueryMatch((*i)->GetTitle(), query_nodes.get()))
+ nodes->push_back(*i);
}
}
+void BookmarkBarModel::Remove(BookmarkBarNode* parent, int index) {
+ if (!loaded_ || !IsValidIndex(parent, index, false) || parent == &root_) {
+ NOTREACHED();
+ return;
+ }
+ RemoveAndDeleteNode(parent->GetChild(index));
+}
+
void BookmarkBarModel::Move(BookmarkBarNode* node,
BookmarkBarNode* new_parent,
int index) {
- DCHECK(node && new_parent);
- DCHECK(node->GetParent());
-#ifndef NDEBUG
- CheckIndex(new_parent, index, true);
-#endif
-
- if (new_parent == &root_ || node == &root_ || node == bookmark_bar_node_ ||
+ if (!loaded_ || !node || !IsValidIndex(new_parent, index, true) ||
+ new_parent == &root_ || node == &root_ || node == bookmark_bar_node_ ||
node == other_node_) {
NOTREACHED();
return;
@@ -218,10 +234,9 @@ void BookmarkBarModel::Move(BookmarkBarNode* node,
index--;
new_parent->Add(index, node);
- HistoryService* history = !profile_ ? NULL :
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (history)
- history->UpdateStarredEntry(node->GetEntry());
+ if (store_.get())
+ store_->ScheduleSave();
+
FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_,
BookmarkNodeMoved(this, old_parent, old_index,
new_parent, index));
@@ -229,47 +244,44 @@ void BookmarkBarModel::Move(BookmarkBarNode* node,
void BookmarkBarModel::SetTitle(BookmarkBarNode* node,
const std::wstring& title) {
- DCHECK(node);
+ if (!node) {
+ NOTREACHED();
+ return;
+ }
if (node->GetTitle() == title)
return;
+
node->SetTitle(title);
- HistoryService* history = !profile_ ? NULL :
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (history)
- history->UpdateStarredEntry(node->GetEntry());
+
+ if (store_.get())
+ store_->ScheduleSave();
+
FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_,
BookmarkNodeChanged(this, node));
}
BookmarkBarNode* BookmarkBarModel::GetNodeByURL(const GURL& url) {
- BookmarkBarNode tmp_node(this);
- tmp_node.url_ = url;
+ BookmarkBarNode tmp_node(this, url);
NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node);
return (i != nodes_ordered_by_url_set_.end()) ? *i : NULL;
}
-BookmarkBarNode* BookmarkBarModel::GetNodeByGroupID(
- history::UIStarID group_id) {
+BookmarkBarNode* BookmarkBarModel::GetNodeByID(int id) {
// TODO(sky): TreeNode needs a method that visits all nodes using a predicate.
- return GetNodeByGroupID(&root_, group_id);
+ return GetNodeByID(&root_, id);
}
BookmarkBarNode* BookmarkBarModel::AddGroup(
BookmarkBarNode* parent,
int index,
const std::wstring& title) {
- DCHECK(IsLoaded());
-#ifndef NDEBUG
- CheckIndex(parent, index, true);
-#endif
- if (parent == &root_) {
+ if (!loaded_ || parent == &root_ || !IsValidIndex(parent, index, true)) {
// Can't add to the root.
NOTREACHED();
return NULL;
}
- BookmarkBarNode* new_node = new BookmarkBarNode(this);
- new_node->group_id_ = next_group_id_++;
+ BookmarkBarNode* new_node = new BookmarkBarNode(this, GURL());
new_node->SetTitle(title);
new_node->type_ = history::StarredEntry::USER_GROUP;
@@ -289,15 +301,11 @@ BookmarkBarNode* BookmarkBarModel::AddURLWithCreationTime(
const std::wstring& title,
const GURL& url,
const Time& creation_time) {
- DCHECK(IsLoaded() && url.is_valid() && parent);
- if (parent == &root_) {
- // Can't add to the root.
+ if (!loaded_ || !url.is_valid() || parent == &root_ ||
+ !IsValidIndex(parent, index, true)) {
NOTREACHED();
return NULL;
}
-#ifndef NDEBUG
- CheckIndex(parent, index, true);
-#endif
BookmarkBarNode* existing_node = GetNodeByURL(url);
if (existing_node) {
@@ -308,9 +316,8 @@ BookmarkBarNode* BookmarkBarModel::AddURLWithCreationTime(
SetDateGroupModified(parent, creation_time);
- BookmarkBarNode* new_node = new BookmarkBarNode(this);
+ BookmarkBarNode* new_node = new BookmarkBarNode(this, url);
new_node->SetTitle(title);
- new_node->SetURL(url);
new_node->date_added_ = creation_time;
new_node->type_ = history::StarredEntry::URL;
@@ -342,139 +349,84 @@ void BookmarkBarModel::FavIconLoaded(BookmarkBarNode* node) {
BookmarkNodeFavIconLoaded(this, node));
}
-void BookmarkBarModel::RemoveNode(BookmarkBarNode* node) {
- DCHECK(node && node != bookmark_bar_node_ && node != other_node_);
+void BookmarkBarModel::RemoveNode(BookmarkBarNode* node,
+ std::set<GURL>* removed_urls) {
+ if (!loaded_ || !node || node == &root_ || node == bookmark_bar_node_ ||
+ node == other_node_) {
+ NOTREACHED();
+ return;
+ }
+
if (node->GetType() == history::StarredEntry::URL) {
NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node);
DCHECK(i != nodes_ordered_by_url_set_.end());
nodes_ordered_by_url_set_.erase(i);
- }
-
- NodeToHandleMap::iterator i = node_to_handle_map_.find(node);
- if (i != node_to_handle_map_.end()) {
- HistoryService* history = !profile_ ? NULL :
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (history)
- request_consumer_.SetClientData(history, i->second, NULL);
- node_to_handle_map_.erase(i);
+ removed_urls->insert(node->GetURL());
}
CancelPendingFavIconLoadRequests(node);
// Recurse through children.
for (int i = node->GetChildCount() - 1; i >= 0; --i)
- RemoveNode(node->GetChild(i));
+ RemoveNode(node->GetChild(i), removed_urls);
}
-void BookmarkBarModel::OnGotStarredEntries(
- HistoryService::Handle,
- std::vector<history::StarredEntry>* entries) {
+void BookmarkBarModel::OnBookmarkStorageLoadedBookmarks(
+ bool file_exists,
+ bool loaded_from_history) {
if (loaded_) {
NOTREACHED();
return;
}
- DCHECK(entries);
- // Create tree nodes for each of the elements.
- PopulateNodes(entries);
-
- // Yes, we've finished loading.
- loaded_ = true;
+ if (file_exists || loaded_from_history || !profile_ ||
+ !profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)) {
+ if (loaded_from_history) {
+ // We were just populated from the historical file. Schedule a save so
+ // that the main file is up to date.
+ store_->ScheduleSave();
+ }
- FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_, Loaded(this));
+ // The file exists, we're loaded.
+ DoneLoading();
+ return;
+ }
- NotificationService::current()->Notify(
- NOTIFY_BOOKMARK_MODEL_LOADED,
- Source<Profile>(profile_),
- NotificationService::NoDetails());
+ // The file doesn't exist. If the bookmarks were in the db the history db
+ // will copy them to a file on init. Schedule an empty request to history so
+ // that we know history will have saved the bookmarks (if it had them). When
+ // the callback is processed
+ // when done we'll try and load the bookmarks again.
+ profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)->
+ ScheduleEmptyCallback(&load_consumer_,
+ NewCallback(this, &BookmarkBarModel::OnHistoryDone));
}
-void BookmarkBarModel::PopulateNodes(
- std::vector<history::StarredEntry>* entries) {
- std::map<history::UIStarID,history::StarID> group_id_to_id_map;
- IDToNodeMap id_to_node_map;
-
- // Iterate through the entries building a mapping between group_id and id as
- // well as creating the bookmark bar node and other node.
- for (std::vector<history::StarredEntry>::const_iterator i = entries->begin();
- i != entries->end(); ++i) {
- if (i->type == history::StarredEntry::URL)
- continue;
-
- if (i->type == history::StarredEntry::OTHER)
- other_node_ = CreateRootNodeFromStarredEntry(*i);
- else if (i->type == history::StarredEntry::BOOKMARK_BAR)
- bookmark_bar_node_ = CreateRootNodeFromStarredEntry(*i);
-
- group_id_to_id_map[i->group_id] = i->id;
+void BookmarkBarModel::OnHistoryDone(HistoryService::Handle handle) {
+ if (loaded_) {
+ NOTREACHED();
+ return;
}
- // Add the bookmark bar and other nodes to the root node.
- AddRootChildren(&id_to_node_map);
-
- // If the db was corrupt and we didn't get the bookmark bar/other nodes,
- // AddRootChildren will create them. Update the map to make sure it includes
- // these nodes.
- group_id_to_id_map[other_node_->group_id_] = other_node_->star_id_;
- group_id_to_id_map[bookmark_bar_node_->group_id_] =
- bookmark_bar_node_->star_id_;
-
- // Iterate through the entries again creating the nodes.
- for (std::vector<history::StarredEntry>::iterator i = entries->begin();
- i != entries->end(); ++i) {
- if (!i->parent_group_id) {
- DCHECK(i->type == history::StarredEntry::BOOKMARK_BAR ||
- i->type == history::StarredEntry::OTHER);
- // Ignore entries not parented to the bookmark bar.
- continue;
- }
+ // If the bookmarks were stored in the db the db will have migrated them to
+ // a file now. Try loading from the file.
+ store_->LoadBookmarks(true);
+}
- BookmarkBarNode* node = id_to_node_map[i->id];
- if (!node) {
- // Creating a node results in creating the parent. As such, it is
- // possible for the node representing a group to have been created before
- // encountering the details.
+void BookmarkBarModel::DoneLoading() {
+ // Update nodes_ordered_by_url_set_ from the nodes.
+ PopulateNodesByURL(&root_);
- // The created nodes are owned by the root node.
- node = new BookmarkBarNode(this);
- id_to_node_map[i->id] = node;
- }
- node->Reset(*i);
-
- DCHECK(group_id_to_id_map.find(i->parent_group_id) !=
- group_id_to_id_map.end());
- history::StarID parent_id = group_id_to_id_map[i->parent_group_id];
- BookmarkBarNode* parent = id_to_node_map[parent_id];
- if (!parent) {
- // Haven't encountered the parent yet, create it now.
- parent = new BookmarkBarNode(this);
- id_to_node_map[parent_id] = parent;
- }
-
- if (i->type == history::StarredEntry::URL)
- nodes_ordered_by_url_set_.insert(node);
- else
- next_group_id_ = std::max(next_group_id_, i->group_id + 1);
+ loaded_ = true;
- // Add the node to its parent. entries is ordered by parent then
- // visual order so that we know we maintain visual order by always adding
- // to the end.
- parent->Add(parent->GetChildCount(), node);
- }
-}
+ // Notify our direct observers.
+ FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_, Loaded(this));
-void BookmarkBarModel::OnCreatedEntry(HistoryService::Handle handle,
- history::StarID id) {
- BookmarkBarNode* node = request_consumer_.GetClientData(
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS), handle);
- // Node is NULL if the node was removed by the user before the request
- // was processed.
- if (node) {
- DCHECK(!node->star_id_);
- node->star_id_ = id;
- DCHECK(node_to_handle_map_.find(node) != node_to_handle_map_.end());
- node_to_handle_map_.erase(node_to_handle_map_.find(node));
- }
+ // And generic notification.
+ NotificationService::current()->Notify(
+ NOTIFY_BOOKMARK_MODEL_LOADED,
+ Source<Profile>(profile_),
+ NotificationService::NoDetails());
}
void BookmarkBarModel::RemoveAndDeleteNode(BookmarkBarNode* delete_me) {
@@ -484,84 +436,79 @@ void BookmarkBarModel::RemoveAndDeleteNode(BookmarkBarNode* delete_me) {
DCHECK(parent);
int index = parent->IndexOfChild(node.get());
parent->Remove(index);
- RemoveNode(node.get());
+ history::URLsStarredDetails details(false);
+ RemoveNode(node.get(), &details.changed_urls);
+
+ if (store_.get())
+ store_->ScheduleSave();
- HistoryService* history = profile_ ?
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS) : NULL;
- if (history) {
- if (node->GetType() == history::StarredEntry::URL) {
- history->DeleteStarredURL(node->GetURL());
- } else {
- history->DeleteStarredGroup(node->GetGroupID());
- }
- }
FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_,
BookmarkNodeRemoved(this, parent, index));
+
+ NotificationService::current()->Notify(NOTIFY_URLS_STARRED,
+ Source<Profile>(profile_),
+ Details<history::URLsStarredDetails>(&details));
}
BookmarkBarNode* BookmarkBarModel::AddNode(BookmarkBarNode* parent,
- int index,
- BookmarkBarNode* node) {
+ int index,
+ BookmarkBarNode* node) {
parent->Add(index, node);
- // NOTE: As history calls us back when we invoke CreateStarredEntry, we have
- // to be sure to invoke it after we've updated the nodes appropriately.
- HistoryService* history = !profile_ ? NULL :
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (history) {
- HistoryService::Handle handle =
- history->CreateStarredEntry(node->GetEntry(), &request_consumer_,
- NewCallback(this, &BookmarkBarModel::OnCreatedEntry));
- request_consumer_.SetClientData(history, handle, node);
- node_to_handle_map_[node] = handle;
- }
+ if (store_.get())
+ store_->ScheduleSave();
+
FOR_EACH_OBSERVER(BookmarkBarModelObserver, observers_,
BookmarkNodeAdded(this, parent, index));
+
+ if (node->GetType() == history::StarredEntry::URL) {
+ history::URLsStarredDetails details(true);
+ details.changed_urls.insert(node->GetURL());
+ NotificationService::current()->Notify(NOTIFY_URLS_STARRED,
+ Source<Profile>(profile_),
+ Details<history::URLsStarredDetails>(&details));
+ }
return node;
}
-BookmarkBarNode* BookmarkBarModel::GetNodeByGroupID(
- BookmarkBarNode* node,
- history::UIStarID group_id) {
- if (node->GetType() == history::StarredEntry::USER_GROUP &&
- node->GetGroupID() == group_id) {
+BookmarkBarNode* BookmarkBarModel::GetNodeByID(BookmarkBarNode* node,
+ int id) {
+ if (node->id() == id)
return node;
- }
+
for (int i = 0; i < node->GetChildCount(); ++i) {
- BookmarkBarNode* result = GetNodeByGroupID(node->GetChild(i), group_id);
+ BookmarkBarNode* result = GetNodeByID(node->GetChild(i), id);
if (result)
return result;
}
return NULL;
}
+bool BookmarkBarModel::IsValidIndex(BookmarkBarNode* parent,
+ int index,
+ bool allow_end) {
+ return (parent &&
+ (index >= 0 && (index < parent->GetChildCount() ||
+ (allow_end && index == parent->GetChildCount()))));
+ }
+
void BookmarkBarModel::SetDateGroupModified(BookmarkBarNode* parent,
const Time time) {
DCHECK(parent);
parent->date_group_modified_ = time;
- HistoryService* history = profile_ ?
- profile_->GetHistoryService(Profile::EXPLICIT_ACCESS) : NULL;
- if (history)
- history->UpdateStarredEntry(parent->GetEntry());
+
+ if (store_.get())
+ store_->ScheduleSave();
}
void BookmarkBarModel::CreateBookmarkBarNode() {
history::StarredEntry entry;
- entry.id = HistoryService::kBookmarkBarID;
- entry.group_id = HistoryService::kBookmarkBarID;
entry.type = history::StarredEntry::BOOKMARK_BAR;
bookmark_bar_node_ = CreateRootNodeFromStarredEntry(entry);
}
void BookmarkBarModel::CreateOtherBookmarksNode() {
history::StarredEntry entry;
- entry.id = HistoryService::kBookmarkBarID;
- for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin();
- i != nodes_ordered_by_url_set_.end(); ++i) {
- entry.id = std::max(entry.id, (*i)->GetStarID());
- }
- entry.id++;
- entry.group_id = next_group_id_++;
entry.type = history::StarredEntry::OTHER;
other_node_ = CreateRootNodeFromStarredEntry(entry);
}
@@ -570,43 +517,15 @@ BookmarkBarNode* BookmarkBarModel::CreateRootNodeFromStarredEntry(
const history::StarredEntry& entry) {
DCHECK(entry.type == history::StarredEntry::BOOKMARK_BAR ||
entry.type == history::StarredEntry::OTHER);
- BookmarkBarNode* node = new BookmarkBarNode(this);
+ BookmarkBarNode* node = new BookmarkBarNode(this, GURL());
node->Reset(entry);
if (entry.type == history::StarredEntry::BOOKMARK_BAR)
node->SetTitle(l10n_util::GetString(IDS_BOOMARK_BAR_FOLDER_NAME));
else
node->SetTitle(l10n_util::GetString(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME));
- next_group_id_ = std::max(next_group_id_, entry.group_id + 1);
return node;
}
-void BookmarkBarModel::AddRootChildren(IDToNodeMap* id_to_node_map) {
- // When invoked we should have created the bookmark bar and other nodes. If
- // not, it indicates the db couldn't be loaded correctly or is corrupt.
- // Force creation so that bookmark bar model is still usable.
- if (!bookmark_bar_node_) {
- LOG(WARNING) << "No bookmark bar entry in the database. This indicates "
- "bookmarks database couldn't be loaded or is corrupt.";
- CreateBookmarkBarNode();
- }
- if (!other_node_) {
- LOG(WARNING) << "No other folders bookmark bar entry in the database. This "
- "indicates bookmarks database couldn't be loaded or is "
- "corrupt.";
- CreateOtherBookmarksNode();
- }
-
- if (id_to_node_map) {
- (*id_to_node_map)[other_node_->GetStarID()] = other_node_;
- (*id_to_node_map)[bookmark_bar_node_->GetStarID()] = bookmark_bar_node_;
- }
-
- // WARNING: order is important here, various places assume bookmark bar then
- // other node.
- root_.Add(0, bookmark_bar_node_);
- root_.Add(1, other_node_);
-}
-
void BookmarkBarModel::OnFavIconDataAvailable(
HistoryService::Handle handle,
bool know_favicon,
@@ -640,6 +559,7 @@ void BookmarkBarModel::LoadFavIcon(BookmarkBarNode* node) {
node->GetURL(), &load_consumer_,
NewCallback(this, &BookmarkBarModel::OnFavIconDataAvailable));
load_consumer_.SetClientData(history_service, handle, node);
+ node->favicon_load_handle_ = handle;
}
void BookmarkBarModel::CancelPendingFavIconLoadRequests(BookmarkBarNode* node) {
@@ -652,17 +572,12 @@ void BookmarkBarModel::CancelPendingFavIconLoadRequests(BookmarkBarNode* node) {
}
}
-// static
-bool BookmarkBarModel::MoreRecentlyModified(BookmarkBarNode* n1,
- BookmarkBarNode* n2) {
- return n1->date_group_modified_ > n2->date_group_modified_;
-}
-
void BookmarkBarModel::GetMostRecentlyModifiedGroupNodes(
BookmarkBarNode* parent,
size_t count,
std::vector<BookmarkBarNode*>* nodes) {
- if (parent->group_id_ && parent->date_group_modified_ > Time()) {
+ if (parent != &root_ && parent->is_folder() &&
+ parent->date_group_modified() > Time()) {
if (count == 0) {
nodes->push_back(parent);
} else {
@@ -679,9 +594,8 @@ void BookmarkBarModel::GetMostRecentlyModifiedGroupNodes(
// (which have a time of 0).
for (int i = 0; i < parent->GetChildCount(); ++i) {
BookmarkBarNode* child = parent->GetChild(i);
- if (child->GetType() != history::StarredEntry::URL) {
+ if (child->is_folder())
GetMostRecentlyModifiedGroupNodes(child, count, nodes);
- }
}
}
@@ -689,7 +603,7 @@ void BookmarkBarModel::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type) {
- case NOTIFY_STARRED_FAVICON_CHANGED: {
+ case NOTIFY_FAVICON_CHANGED: {
// Prevent the observers from getting confused for multiple favicon loads.
Details<history::FavIconChangeDetails> favicon_details(details);
for (std::set<GURL>::const_iterator i = favicon_details->urls.begin();
@@ -711,3 +625,10 @@ void BookmarkBarModel::Observe(NotificationType type,
break;
}
}
+
+void BookmarkBarModel::PopulateNodesByURL(BookmarkBarNode* node) {
+ if (node->is_url())
+ nodes_ordered_by_url_set_.insert(node);
+ for (int i = 0; i < node->GetChildCount(); ++i)
+ PopulateNodesByURL(node->GetChild(i));
+}
diff --git a/chrome/browser/bookmark_bar_model.h b/chrome/browser/bookmark_bar_model.h
index f7ecf71..a481004 100644
--- a/chrome/browser/bookmark_bar_model.h
+++ b/chrome/browser/bookmark_bar_model.h
@@ -31,6 +31,7 @@
#define CHROME_BROWSER_BOOKMARK_BAR_MODEL_H_
#include "base/observer_list.h"
+#include "chrome/browser/bookmark_storage.h"
#include "chrome/browser/cancelable_request.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/history_types.h"
@@ -43,6 +44,10 @@ class BookmarkBarModel;
class BookmarkCodec;
class Profile;
+namespace history {
+class StarredURLDatabase;
+}
+
// BookmarkBarNode ------------------------------------------------------------
// BookmarkBarNode contains information about a starred entry: title, URL,
@@ -52,9 +57,11 @@ class Profile;
class BookmarkBarNode : public ChromeViews::TreeNode<BookmarkBarNode> {
friend class BookmarkBarModel;
friend class BookmarkCodec;
+ friend class history::StarredURLDatabase;
+ FRIEND_TEST(BookmarkBarModelTest, MostRecentlyAddedEntries);
public:
- explicit BookmarkBarNode(BookmarkBarModel* model);
+ BookmarkBarNode(BookmarkBarModel* model, const GURL& url);
virtual ~BookmarkBarNode() {}
@@ -65,21 +72,15 @@ class BookmarkBarNode : public ChromeViews::TreeNode<BookmarkBarNode> {
// Returns the URL.
const GURL& GetURL() const { return url_; }
- // Returns the start ID corresponding to this node.
- // TODO(sky): bug 1256202, make this an ever increasing integer assigned on
- // reading, but not archived. Best to set it automatically in the constructor.
- history::StarID GetStarID() const { return star_id_; }
+ // Returns a unique id for this node.
+ //
+ // NOTE: this id is only unique for the session and NOT unique across
+ // sessions. Don't persist it!
+ int id() const { return id_; }
// Returns the type of this node.
history::StarredEntry::Type GetType() const { return type_; }
- // Returns a StarredEntry for the node.
- history::StarredEntry GetEntry();
-
- // Returns the ID of group.
- // TODO(sky): bug 1256202, nuke this.
- history::UIStarID GetGroupID() { return group_id_; }
-
// Called when the favicon becomes invalid.
void InvalidateFavicon() {
loaded_favicon_ = false;
@@ -93,18 +94,22 @@ class BookmarkBarNode : public ChromeViews::TreeNode<BookmarkBarNode> {
// for folders (including the bookmark and other folder).
Time date_group_modified() const { return date_group_modified_; }
+ // Convenience for testing if this nodes represents a group. A group is
+ // a node whose type is not URL.
+ bool is_folder() const { return type_ != history::StarredEntry::URL; }
+
+ // Is this a URL?
+ bool is_url() const { return type_ == history::StarredEntry::URL; }
+
private:
// Resets the properties of the node from the supplied entry.
void Reset(const history::StarredEntry& entry);
- // Resets the URL. Take care to cancel loading before invoking this.
- void SetURL(const GURL& url);
-
- // The model.
+ // The model. This is NULL when created by StarredURLDatabase for migration.
BookmarkBarModel* model_;
// Unique identifier for this node.
- history::StarID star_id_;
+ const int id_;
// Whether the favicon has been loaded.
bool loaded_favicon_;
@@ -116,16 +121,14 @@ class BookmarkBarNode : public ChromeViews::TreeNode<BookmarkBarNode> {
// from the HistoryService.
HistoryService::Handle favicon_load_handle_;
- // URL.
- GURL url_;
+ // The URL. BookmarkBarModel maintains maps off this URL, it is important that
+ // it not change once the node has been created.
+ const GURL url_;
// Type of node.
// TODO(sky): bug 1256202, convert this into a type defined here.
history::StarredEntry::Type type_;
- // Group ID.
- history::UIStarID group_id_;
-
// Date we were created.
Time date_added_;
@@ -189,6 +192,7 @@ class BookmarkBarModelObserver {
class BookmarkBarModel : public NotificationObserver {
friend class BookmarkBarNode;
friend class BookmarkBarModelTest;
+ friend class BookmarkStorage;
public:
explicit BookmarkBarModel(Profile* profile);
@@ -212,6 +216,14 @@ class BookmarkBarModel : public NotificationObserver {
// modified groups. This never returns an empty vector.
std::vector<BookmarkBarNode*> GetMostRecentlyModifiedGroups(size_t max_count);
+ // Returns the most recently added bookmarks.
+ void GetMostRecentlyAddedEntries(size_t count,
+ std::vector<BookmarkBarNode*>* nodes);
+
+ // Returns the bookmarks whose title contains text.
+ void GetBookmarksMatchingText(const std::wstring& text,
+ std::vector<BookmarkBarNode*>* nodes);
+
void AddObserver(BookmarkBarModelObserver* observer) {
observers_.AddObserver(observer);
}
@@ -224,12 +236,6 @@ class BookmarkBarModel : public NotificationObserver {
// unstars all nodes. Observers are notified immediately.
void Remove(BookmarkBarNode* parent, int index);
- // If the specified node is on the bookmark bar it is removed from the
- // bookmark bar to be a child of the other node. If the node is not on the
- // bookmark bar this does nothing. This is a convenience for invoking
- // Move to the other node.
- void RemoveFromBookmarkBar(BookmarkBarNode* node);
-
// Moves the specified entry to a new location.
void Move(BookmarkBarNode* node, BookmarkBarNode* new_parent, int index);
@@ -243,9 +249,14 @@ class BookmarkBarModel : public NotificationObserver {
// the specified URL.
BookmarkBarNode* GetNodeByURL(const GURL& url);
- // Returns the node with the specified group id, or NULL if there is no node
- // with the specified id.
- BookmarkBarNode* GetNodeByGroupID(history::UIStarID group_id);
+ // Returns true if there is a bookmark for the specified URL.
+ bool IsBookmarked(const GURL& url) {
+ return GetNodeByURL(url) != NULL;
+ }
+
+ // Returns the node with the specified id, or NULL if there is no node with
+ // the specified id.
+ BookmarkBarNode* GetNodeByID(int id);
// Adds a new group node at the specified position.
BookmarkBarNode* AddGroup(BookmarkBarNode* parent,
@@ -287,30 +298,38 @@ class BookmarkBarModel : public NotificationObserver {
}
};
- // Maps from star id of node to actual node. Used during creation of nodes
- // from history::StarredEntries.
- typedef std::map<history::StarID,BookmarkBarNode*> IDToNodeMap;
-
// Overriden to notify the observer the favicon has been loaded.
void FavIconLoaded(BookmarkBarNode* node);
- // NOTE: this does NOT override EntryAdded/EntryChanged as we assume all
- // mutation to entries on the bookmark bar occurs through our methods.
-
- // Removes the node for internal maps. This does NOT delete the node.
- void RemoveNode(BookmarkBarNode* node);
-
- // Callback from the database with the starred entries. Adds the appropriate
- // entries to the root node.
- void OnGotStarredEntries(HistoryService::Handle,
- std::vector<history::StarredEntry>* entries);
+ // Removes the node from internal maps and recurces through all children. If
+ // the node is a url, its url is added to removed_urls.
+ //
+ // This does NOT delete the node.
+ void RemoveNode(BookmarkBarNode* node, std::set<GURL>* removed_urls);
+
+ // Callback from BookmarkStorage that it has finished loading. This method
+ // may be hit twice. In particular, on construction BookmarkBarModel asks
+ // BookmarkStorage to load the bookmarks. BookmarkStorage invokes this method
+ // with loaded_from_history false and file_exists indicating whether the
+ // bookmarks file exists. If the file doesn't exist, we query history. When
+ // history calls us back (OnHistoryDone) we then ask BookmarkStorage to load
+ // from the migration file. BookmarkStorage again invokes this method, but
+ // with |loaded_from_history| true.
+ void OnBookmarkStorageLoadedBookmarks(bool file_exists,
+ bool loaded_from_history);
+
+ // Used for migrating bookmarks from history to standalone file.
+ //
+ // Callback from history that it is done with an empty request. This is used
+ // if there is no bookmarks file. Once done, we attempt to load from the
+ // temporary file creating during migration.
+ void OnHistoryDone(HistoryService::Handle handle);
- // Invoked from OnGotStarredEntries to create all the BookmarkNodes for
- // the specified entries.
- void PopulateNodes(std::vector<history::StarredEntry>* entries);
+ // Invoked when loading is finished. Sets loaded_ and notifies observers.
+ void DoneLoading();
- // Callback from AddFolder/AddURL.
- void OnCreatedEntry(HistoryService::Handle handle, history::StarID id);
+ // Populates nodes_ordered_by_url_set_ from root.
+ void PopulateNodesByURL(BookmarkBarNode* node);
// Removes the node from its parent, sends notification, and deletes it.
// type specifies how the node should be removed.
@@ -321,36 +340,22 @@ class BookmarkBarModel : public NotificationObserver {
int index,
BookmarkBarNode* node);
- // Implementation of GetNodeByGrouID.
- BookmarkBarNode* GetNodeByGroupID(BookmarkBarNode* node,
- history::UIStarID group_id);
-
- // Adds the bookmark bar and other nodes to the root node. If id_to_node_map
- // is non-null, the bookmark bar node and other bookmark nodes are added to
- // it.
- void AddRootChildren(IDToNodeMap* id_to_node_map);
-
-#ifndef NDEBUG
- void CheckIndex(BookmarkBarNode* parent, int index, bool allow_end) {
- DCHECK(parent);
- DCHECK(index >= 0 &&
- (index < parent->GetChildCount() ||
- allow_end && index == parent->GetChildCount()));
- }
-#endif
+ // Implementation of GetNodeByID.
+ BookmarkBarNode* GetNodeByID(BookmarkBarNode* node, int id);
+
+ // Returns true if the parent and index are valid.
+ bool IsValidIndex(BookmarkBarNode* parent, int index, bool allow_end);
// Sets the date modified time of the specified node.
void SetDateGroupModified(BookmarkBarNode* parent, const Time time);
- // Creates the bookmark bar/other nodes. This is used during testing (when we
- // don't load from the DB), as well as if the db doesn't give us back a
- // bookmark bar or other node (which should only happen if there is an error
- // in loading the DB).
+ // Creates the bookmark bar/other nodes. These call into
+ // CreateRootNodeFromStarredEntry.
void CreateBookmarkBarNode();
void CreateOtherBookmarksNode();
// Creates a root node (either the bookmark bar node or other node) from the
- // specified starred entry. Only used once when loading.
+ // specified starred entry.
BookmarkBarNode* CreateRootNodeFromStarredEntry(
const history::StarredEntry& entry);
@@ -370,9 +375,6 @@ class BookmarkBarModel : public NotificationObserver {
// If we're waiting on a favicon for node, the load request is canceled.
void CancelPendingFavIconLoadRequests(BookmarkBarNode* node);
- // Returns true if n1's date modified time is newer than n2s.
- static bool MoreRecentlyModified(BookmarkBarNode* n1, BookmarkBarNode* n2);
-
// Returns up to count of the most recently modified groups. This may not
// add anything.
void GetMostRecentlyModifiedGroupNodes(BookmarkBarNode* parent,
@@ -404,26 +406,12 @@ class BookmarkBarModel : public NotificationObserver {
typedef std::set<BookmarkBarNode*,NodeURLComparator> NodesOrderedByURLSet;
NodesOrderedByURLSet nodes_ordered_by_url_set_;
- // Maps from node to request handle. This is used when creating new nodes.
- typedef std::map<BookmarkBarNode*,HistoryService::Handle> NodeToHandleMap;
- NodeToHandleMap node_to_handle_map_;
-
- // Used when creating new entries/groups. Maps to the newly created
- // node.
- CancelableRequestConsumerT<BookmarkBarNode*,NULL> request_consumer_;
-
- // ID of the next group we create.
- //
- // After the first load, this is set to the max group_id from the database.
- //
- // This value is incremented every time a new group is created. It is
- // important that the value assigned to a group node remain unique during
- // a run of Chrome (BookmarkEditorView for one relies on this).
- history::StarID next_group_id_;
-
- // Used for loading favicons.
+ // Used for loading favicons and the empty history request.
CancelableRequestConsumerT<BookmarkBarNode*, NULL> load_consumer_;
+ // Reads/writes bookmarks to disk.
+ scoped_refptr<BookmarkStorage> store_;
+
DISALLOW_EVIL_CONSTRUCTORS(BookmarkBarModel);
};
diff --git a/chrome/browser/bookmark_bar_model_unittest.cc b/chrome/browser/bookmark_bar_model_unittest.cc
index 5a95963..2f52e19 100644
--- a/chrome/browser/bookmark_bar_model_unittest.cc
+++ b/chrome/browser/bookmark_bar_model_unittest.cc
@@ -28,10 +28,10 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "base/string_util.h"
-#ifdef USE_BOOKMARK_CODEC
#include "chrome/browser/bookmark_codec.h"
-#endif // USE_BOOKMARK_CODEC
#include "chrome/browser/bookmark_bar_model.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
#include "chrome/test/testing_profile.h"
#include "chrome/views/tree_node_model.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -130,10 +130,6 @@ class BookmarkBarModelTest : public testing::Test,
ASSERT_EQ(changed_count, this->changed_count);
}
- history::UIStarID GetMaxGroupID() {
- return GetMaxGroupID(model.root_node());
- }
-
void AssertNodesEqual(BookmarkBarNode* expected, BookmarkBarNode* actual) {
ASSERT_TRUE(expected);
ASSERT_TRUE(actual);
@@ -170,26 +166,20 @@ class BookmarkBarModelTest : public testing::Test,
int changed_count;
ObserverDetails observer_details;
-
- private:
- history::UIStarID GetMaxGroupID(BookmarkBarNode* node) {
- history::UIStarID max_id = node->GetGroupID();
- for (int i = 0; i < node->GetChildCount(); ++i) {
- max_id = std::max(max_id, GetMaxGroupID(node->GetChild(i)));
- }
- return max_id;
- }
-
- DISALLOW_EVIL_CONSTRUCTORS(BookmarkBarModelTest);
};
TEST_F(BookmarkBarModelTest, InitialState) {
- BookmarkBarNode* root = model.GetBookmarkBarNode();
- ASSERT_TRUE(root != NULL);
- ASSERT_EQ(0, root->GetChildCount());
- ASSERT_EQ(history::StarredEntry::BOOKMARK_BAR, root->GetType());
- ASSERT_EQ(HistoryService::kBookmarkBarID, root->GetStarID());
- ASSERT_EQ(HistoryService::kBookmarkBarID, root->GetGroupID());
+ BookmarkBarNode* bb_node = model.GetBookmarkBarNode();
+ ASSERT_TRUE(bb_node != NULL);
+ EXPECT_EQ(0, bb_node->GetChildCount());
+ EXPECT_EQ(history::StarredEntry::BOOKMARK_BAR, bb_node->GetType());
+
+ BookmarkBarNode* other_node = model.other_node();
+ ASSERT_TRUE(other_node != NULL);
+ EXPECT_EQ(0, other_node->GetChildCount());
+ EXPECT_EQ(history::StarredEntry::OTHER, other_node->GetType());
+
+ EXPECT_TRUE(bb_node->id() != other_node->id());
}
TEST_F(BookmarkBarModelTest, AddURL) {
@@ -206,19 +196,14 @@ TEST_F(BookmarkBarModelTest, AddURL) {
ASSERT_TRUE(url == new_node->GetURL());
ASSERT_EQ(history::StarredEntry::URL, new_node->GetType());
ASSERT_TRUE(new_node == model.GetNodeByURL(url));
- ASSERT_EQ(new_node->GetGroupID(), new_node->GetEntry().group_id);
- ASSERT_EQ(new_node->GetTitle(), new_node->GetEntry().title);
- ASSERT_EQ(new_node->GetParent()->GetGroupID(),
- new_node->GetEntry().parent_group_id);
- ASSERT_EQ(0, new_node->GetEntry().visual_order);
- ASSERT_TRUE(new_node->GetURL() == new_node->GetEntry().url);
- ASSERT_EQ(history::StarredEntry::URL, new_node->GetEntry().type);
+
+ EXPECT_TRUE(new_node->id() != root->id() &&
+ new_node->id() != model.other_node()->id());
}
TEST_F(BookmarkBarModelTest, AddGroup) {
BookmarkBarNode* root = model.GetBookmarkBarNode();
const std::wstring title(L"foo");
- const history::UIStarID max_group_id = GetMaxGroupID();
BookmarkBarNode* new_node = model.AddGroup(root, 0, title);
AssertObserverCount(1, 0, 0, 0);
@@ -227,20 +212,15 @@ TEST_F(BookmarkBarModelTest, AddGroup) {
ASSERT_EQ(1, root->GetChildCount());
ASSERT_EQ(title, new_node->GetTitle());
ASSERT_EQ(history::StarredEntry::USER_GROUP, new_node->GetType());
- ASSERT_EQ(max_group_id + 1, new_node->GetGroupID());
- ASSERT_EQ(new_node->GetGroupID(), new_node->GetEntry().group_id);
- ASSERT_EQ(new_node->GetTitle(), new_node->GetEntry().title);
- ASSERT_EQ(new_node->GetParent()->GetGroupID(),
- new_node->GetEntry().parent_group_id);
- ASSERT_EQ(0, new_node->GetEntry().visual_order);
- ASSERT_EQ(history::StarredEntry::USER_GROUP, new_node->GetEntry().type);
+
+ EXPECT_TRUE(new_node->id() != root->id() &&
+ new_node->id() != model.other_node()->id());
// Add another group, just to make sure group_ids are incremented correctly.
ClearCounts();
BookmarkBarNode* new_node2 = model.AddGroup(root, 0, title);
AssertObserverCount(1, 0, 0, 0);
observer_details.AssertEquals(root, NULL, 0, -1);
- ASSERT_EQ(max_group_id + 2, new_node2->GetGroupID());
}
TEST_F(BookmarkBarModelTest, RemoveURL) {
@@ -282,15 +262,6 @@ TEST_F(BookmarkBarModelTest, RemoveGroup) {
ASSERT_TRUE(model.GetNodeByURL(url) == NULL);
}
-TEST_F(BookmarkBarModelTest, VisualOrderIncrements) {
- BookmarkBarNode* root = model.GetBookmarkBarNode();
- BookmarkBarNode* group1 = model.AddGroup(root, 0, L"foo");
- EXPECT_EQ(0, group1->GetEntry().visual_order);
- BookmarkBarNode* group2 = model.AddGroup(root, 0, L"foo");
- EXPECT_EQ(1, group1->GetEntry().visual_order);
- EXPECT_EQ(0, group2->GetEntry().visual_order);
-}
-
TEST_F(BookmarkBarModelTest, SetTitle) {
BookmarkBarNode* root = model.GetBookmarkBarNode();
std::wstring title(L"foo");
@@ -333,22 +304,6 @@ TEST_F(BookmarkBarModelTest, Move) {
EXPECT_EQ(0, root->GetChildCount());
}
-TEST_F(BookmarkBarModelTest, RemoveFromBookmarkBar) {
- BookmarkBarNode* root = model.GetBookmarkBarNode();
- const std::wstring title(L"foo");
- const GURL url("http://foo.com");
-
- BookmarkBarNode* new_node = model.AddURL(root, 0, title, url);
-
- ClearCounts();
-
- model.RemoveFromBookmarkBar(new_node);
- AssertObserverCount(0, 1, 0, 0);
- observer_details.AssertEquals(root, model.other_node(), 0, 0);
-
- ASSERT_EQ(0, root->GetChildCount());
-}
-
// Tests that adding a URL to a folder updates the last modified time.
TEST_F(BookmarkBarModelTest, ParentForNewNodes) {
ASSERT_EQ(model.GetBookmarkBarNode(), model.GetParentForNewNodes());
@@ -383,6 +338,42 @@ TEST_F(BookmarkBarModelTest, MostRecentlyModifiedGroups) {
ASSERT_TRUE(most_recent_groups[0] != group);
}
+// Make sure MostRecentlyAddedEntries stays in sync.
+TEST_F(BookmarkBarModelTest, MostRecentlyAddedEntries) {
+ // Add a couple of nodes such that the following holds for the time of the
+ // nodes: n1 > n2 > n3 > n4.
+ Time base_time = Time::Now();
+ BookmarkBarNode* n1 = model.AddURL(
+ model.GetBookmarkBarNode(), 0, L"blah", GURL("http://foo.com/0"));
+ BookmarkBarNode* n2 = model.AddURL(
+ model.GetBookmarkBarNode(), 1, L"blah", GURL("http://foo.com/1"));
+ BookmarkBarNode* n3 = model.AddURL(
+ model.GetBookmarkBarNode(), 2, L"blah", GURL("http://foo.com/2"));
+ BookmarkBarNode* n4 = model.AddURL(
+ model.GetBookmarkBarNode(), 3, L"blah", GURL("http://foo.com/3"));
+ n1->date_added_ = base_time + TimeDelta::FromDays(4);
+ n2->date_added_ = base_time + TimeDelta::FromDays(3);
+ n3->date_added_ = base_time + TimeDelta::FromDays(2);
+ n4->date_added_ = base_time + TimeDelta::FromDays(1);
+
+ // Make sure order is honored.
+ std::vector<BookmarkBarNode*> recently_added;
+ model.GetMostRecentlyAddedEntries(2, &recently_added);
+ ASSERT_EQ(2, recently_added.size());
+ ASSERT_TRUE(n1 == recently_added[0]);
+ ASSERT_TRUE(n2 == recently_added[1]);
+
+ // swap 1 and 2, then check again.
+ recently_added.clear();
+ std::swap(n1->date_added_, n2->date_added_);
+ model.GetMostRecentlyAddedEntries(4, &recently_added);
+ ASSERT_EQ(4, recently_added.size());
+ ASSERT_TRUE(n2 == recently_added[0]);
+ ASSERT_TRUE(n1 == recently_added[1]);
+ ASSERT_TRUE(n3 == recently_added[2]);
+ ASSERT_TRUE(n4 == recently_added[3]);
+}
+
namespace {
// See comment in PopulateNodeFromString.
@@ -471,11 +462,9 @@ static void PopulateBookmarkBarNode(TestNode* parent,
class BookmarkBarModelTestWithProfile : public testing::Test,
public BookmarkBarModelObserver {
public:
- BookmarkBarModelTestWithProfile() {}
-
virtual void SetUp() {
profile_.reset(new TestingProfile());
- profile_->CreateHistoryService();
+ profile_->CreateHistoryService(true);
}
virtual void TearDown() {
@@ -489,19 +478,21 @@ class BookmarkBarModelTestWithProfile : public testing::Test,
// Verifies the contents of the bookmark bar node match the contents of the
// TestNode.
void VerifyModelMatchesNode(TestNode* expected, BookmarkBarNode* actual) {
- EXPECT_EQ(expected->GetChildCount(), actual->GetChildCount());
+ ASSERT_EQ(expected->GetChildCount(), actual->GetChildCount());
for (int i = 0; i < expected->GetChildCount(); ++i) {
TestNode* expected_child = expected->GetChild(i);
BookmarkBarNode* actual_child = actual->GetChild(i);
- EXPECT_EQ(expected_child->GetTitle(), actual_child->GetTitle());
+ ASSERT_EQ(expected_child->GetTitle(), actual_child->GetTitle());
if (expected_child->value == history::StarredEntry::USER_GROUP) {
- EXPECT_TRUE(actual_child->GetType() ==
+ ASSERT_TRUE(actual_child->GetType() ==
history::StarredEntry::USER_GROUP);
// Recurse throught children.
VerifyModelMatchesNode(expected_child, actual_child);
+ if (HasFatalFailure())
+ return;
} else {
// No need to check the URL, just the title is enough.
- EXPECT_TRUE(actual_child->GetType() ==
+ ASSERT_TRUE(actual_child->GetType() ==
history::StarredEntry::URL);
}
}
@@ -510,12 +501,13 @@ class BookmarkBarModelTestWithProfile : public testing::Test,
// Creates the bookmark bar model. If the bookmark bar model has already been
// created a new one is created and the old one destroyed.
void CreateBookmarkBarModel() {
- // NOTE: this order is important. We need to make sure the backend has
- // processed all pending requests from the current BookmarkBarModel before
- // destroying it. By creating a new BookmarkBarModel first and blocking
- // until done, we ensure all requests from the old model have completed.
+ bb_model_.reset(NULL);
+
BookmarkBarModel* new_model = new BookmarkBarModel(profile_.get());
- BlockTillLoaded(new_model);
+ if (!new_model->IsLoaded())
+ BlockTillLoaded(new_model);
+ else
+ new_model->AddObserver(this);
bb_model_.reset(new_model);
}
@@ -526,7 +518,7 @@ class BookmarkBarModelTestWithProfile : public testing::Test,
// Need to shutdown the old one before creating a new one.
profile_.reset(NULL);
profile_.reset(new TestingProfile());
- profile_->CreateHistoryService();
+ profile_->CreateHistoryService(true);
}
scoped_ptr<BookmarkBarModel> bb_model_;
@@ -558,8 +550,6 @@ class BookmarkBarModelTestWithProfile : public testing::Test,
BookmarkBarNode* node) {}
virtual void BookmarkNodeFavIconLoaded(BookmarkBarModel* model,
BookmarkBarNode* node) {}
-
- DISALLOW_EVIL_CONSTRUCTORS(BookmarkBarModelTestWithProfile);
};
// Creates a set of nodes in the bookmark bar model, then recreates the
@@ -601,44 +591,113 @@ TEST_F(BookmarkBarModelTestWithProfile, CreateAndRestore) {
}
}
-#ifdef USE_BOOKMARK_CODEC
-// Creates a set of nodes in the bookmark bar model, then recreates the
-// bookmark bar model which triggers loading from the db and checks the loaded
-// structure to make sure it is what we first created.
-TEST_F(BookmarkBarModelTest, TestJSONCodec) {
- struct TestData {
- // Structure of the children of the bookmark bar model node.
- const std::wstring bbn_contents;
- // Structure of the children of the other node.
- const std::wstring other_contents;
- } data[] = {
- // See PopulateNodeFromString for a description of these strings.
- { L"", L"" },
- { L"a", L"b" },
- { L"a [ b ]", L"" },
- { L"", L"[ b ] a [ c [ d e [ f ] ] ]" },
- { L"a [ b ]", L"" },
- { L"a b c [ d e [ f ] ]", L"g h i [ j k [ l ] ]"},
- };
- for (int i = 0; i < arraysize(data); ++i) {
- BookmarkBarModel expected_model(NULL);
-
- TestNode bbn;
- PopulateNodeFromString(data[i].bbn_contents, &bbn);
- PopulateBookmarkBarNode(&bbn, &expected_model,
- expected_model.GetBookmarkBarNode());
-
- TestNode other;
- PopulateNodeFromString(data[i].other_contents, &other);
- PopulateBookmarkBarNode(&other, &expected_model,
- expected_model.other_node());
-
- BookmarkBarModel actual_model(NULL);
- BookmarkCodec codec;
- scoped_ptr<Value> encoded_value(codec.Encode(&expected_model));
- codec.Decode(&actual_model, *(encoded_value.get()));
+// Test class that creates a BookmarkBarModel with a real history backend.
+class BookmarkBarModelTestWithProfile2 :
+ public BookmarkBarModelTestWithProfile {
+ public:
+ virtual void SetUp() {
+ profile_.reset(new TestingProfile());
+ }
- AssertModelsEqual(&expected_model, &actual_model);
+ protected:
+ // Verifies the state of the model matches that of the state in the saved
+ // history file.
+ void VerifyExpectedState() {
+ // Here's the structure we expect:
+ // bbn
+ // www.google.com - Google
+ // F1
+ // http://www.google.com/intl/en/ads/ - Google Advertising
+ // F11
+ // http://www.google.com/services/ - Google Business Solutions
+ // other
+ // OF1
+ // http://www.google.com/intl/en/about.html - About Google
+ BookmarkBarNode* bbn = bb_model_->GetBookmarkBarNode();
+ ASSERT_EQ(2, bbn->GetChildCount());
+
+ BookmarkBarNode* child = bbn->GetChild(0);
+ ASSERT_EQ(history::StarredEntry::URL, child->GetType());
+ ASSERT_EQ(L"Google", child->GetTitle());
+ ASSERT_TRUE(child->GetURL() == GURL("http://www.google.com"));
+
+ child = bbn->GetChild(1);
+ ASSERT_TRUE(child->is_folder());
+ ASSERT_EQ(L"F1", child->GetTitle());
+ ASSERT_EQ(2, child->GetChildCount());
+
+ BookmarkBarNode* parent = child;
+ child = parent->GetChild(0);
+ ASSERT_EQ(history::StarredEntry::URL, child->GetType());
+ ASSERT_EQ(L"Google Advertising", child->GetTitle());
+ ASSERT_TRUE(child->GetURL() == GURL("http://www.google.com/intl/en/ads/"));
+
+ child = parent->GetChild(1);
+ ASSERT_TRUE(child->is_folder());
+ ASSERT_EQ(L"F11", child->GetTitle());
+ ASSERT_EQ(1, child->GetChildCount());
+
+ parent = child;
+ child = parent->GetChild(0);
+ ASSERT_EQ(history::StarredEntry::URL, child->GetType());
+ ASSERT_EQ(L"Google Business Solutions", child->GetTitle());
+ ASSERT_TRUE(child->GetURL() == GURL("http://www.google.com/services/"));
+
+ parent = bb_model_->other_node();
+ ASSERT_EQ(2, parent->GetChildCount());
+
+ child = parent->GetChild(0);
+ ASSERT_TRUE(child->is_folder());
+ ASSERT_EQ(L"OF1", child->GetTitle());
+ ASSERT_EQ(0, child->GetChildCount());
+
+ child = parent->GetChild(1);
+ ASSERT_EQ(history::StarredEntry::URL, child->GetType());
+ ASSERT_EQ(L"About Google", child->GetTitle());
+ ASSERT_TRUE(child->GetURL() ==
+ GURL("http://www.google.com/intl/en/about.html"));
+
+ ASSERT_TRUE(bb_model_->GetNodeByURL(GURL("http://www.google.com")) != NULL);
}
+};
+
+// Tests migrating bookmarks from db into file. This copies an old history db
+// file containing bookmarks and make sure they are loaded correctly and
+// persisted correctly.
+TEST_F(BookmarkBarModelTestWithProfile2, MigrateFromDBToFileTest) {
+ // Copy db file over that contains starred table.
+ std::wstring old_history_path;
+ PathService::Get(chrome::DIR_TEST_DATA, &old_history_path);
+ file_util::AppendToPath(&old_history_path, L"bookmarks");
+ file_util::AppendToPath(&old_history_path, L"History_with_starred");
+ std::wstring new_history_path = profile_->GetPath();
+ file_util::Delete(new_history_path, true);
+ file_util::CreateDirectory(new_history_path);
+ file_util::AppendToPath(&new_history_path, chrome::kHistoryFilename);
+ file_util::CopyFile(old_history_path, new_history_path);
+
+ // Create the history service making sure it doesn't blow away the file we
+ // just copied.
+ profile_->CreateHistoryService(false);
+
+ CreateBookmarkBarModel();
+
+ // Make sure we loaded OK.
+ VerifyExpectedState();
+ if (HasFatalFailure())
+ return;
+
+ // Create again. This time we shouldn't load from history at all.
+ CreateBookmarkBarModel();
+
+ // Make sure we loaded OK.
+ VerifyExpectedState();
+ if (HasFatalFailure())
+ return;
+
+ // Recreate the history service (with a clean db). Do this just to make sure
+ // we're loading correctly from the bookmarks file.
+ profile_->CreateHistoryService(true);
+ CreateBookmarkBarModel();
+ VerifyExpectedState();
}
-#endif // USE_BOOKMARK_CODEC
diff --git a/chrome/browser/bookmark_codec.cc b/chrome/browser/bookmark_codec.cc
index 37f0ed0..d82a9e2 100644
--- a/chrome/browser/bookmark_codec.cc
+++ b/chrome/browser/bookmark_codec.cc
@@ -34,9 +34,11 @@
#include "chrome/browser/bookmark_bar_model.h"
#include "googleurl/src/gurl.h"
+#include "generated_resources.h"
+
// Key names.
static const wchar_t* kRootsKey = L"roots";
-static const wchar_t* kRootFolderNameKey = L"root";
+static const wchar_t* kRootFolderNameKey = L"bookmark_bar";
static const wchar_t* kOtherBookmarFolderNameKey = L"other";
static const wchar_t* kVersionKey = L"version";
static const wchar_t* kTypeKey = L"type";
@@ -54,9 +56,14 @@ static const wchar_t* kTypeFolder = L"folder";
static const int kCurrentVersion = 1;
Value* BookmarkCodec::Encode(BookmarkBarModel* model) {
+ return Encode(model->GetBookmarkBarNode(), model->other_node());
+}
+
+Value* BookmarkCodec::Encode(BookmarkBarNode* bookmark_bar_node,
+ BookmarkBarNode* other_folder_node) {
DictionaryValue* roots = new DictionaryValue();
- roots->Set(kRootFolderNameKey, EncodeNode(model->GetBookmarkBarNode()));
- roots->Set(kOtherBookmarFolderNameKey, EncodeNode(model->other_node()));
+ roots->Set(kRootFolderNameKey, EncodeNode(bookmark_bar_node));
+ roots->Set(kOtherBookmarFolderNameKey, EncodeNode(other_folder_node));
DictionaryValue* main = new DictionaryValue();
main->SetInteger(kVersionKey, kCurrentVersion);
@@ -91,12 +98,18 @@ bool BookmarkCodec::Decode(BookmarkBarModel* model, const Value& value) {
return false; // Invalid type for root folder and/or other folder.
DecodeNode(model, *static_cast<DictionaryValue*>(root_folder_value),
- model->GetBookmarkBarNode());
+ NULL, model->GetBookmarkBarNode());
DecodeNode(model, *static_cast<DictionaryValue*>(other_folder_value),
- model->other_node());
- // Need to reset these as Decode sets the type to FOLDER.
+ NULL, model->other_node());
+ // Need to reset the type as decoding resets the type to FOLDER. Similarly
+ // we need to reset the title as the title is persisted and restored from
+ // the file.
model->GetBookmarkBarNode()->type_ = history::StarredEntry::BOOKMARK_BAR;
model->other_node()->type_ = history::StarredEntry::OTHER;
+ model->GetBookmarkBarNode()->SetTitle(
+ l10n_util::GetString(IDS_BOOMARK_BAR_FOLDER_NAME));
+ model->other_node()->SetTitle(
+ l10n_util::GetString(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME));
return true;
}
@@ -134,27 +147,26 @@ bool BookmarkCodec::DecodeChildren(BookmarkBarModel* model,
if (child_value->GetType() != Value::TYPE_DICTIONARY)
return false;
- BookmarkBarNode* child = new BookmarkBarNode(model);
- parent->Add(static_cast<int>(i), child);
- if (!DecodeNode(model, *static_cast<DictionaryValue*>(child_value), child))
+ if (!DecodeNode(model, *static_cast<DictionaryValue*>(child_value), parent,
+ NULL)) {
return false;
+ }
}
return true;
}
bool BookmarkCodec::DecodeNode(BookmarkBarModel* model,
const DictionaryValue& value,
+ BookmarkBarNode* parent,
BookmarkBarNode* node) {
+ bool created_node = (node == NULL);
std::wstring title;
if (!value.GetString(kNameKey, &title))
return false;
- node->SetTitle(title);
std::wstring date_added_string;
if (!value.GetString(kDateAddedKey, &date_added_string))
return false;
- node->date_added_ =
- Time::FromInternalValue(StringToInt64(date_added_string));
std::wstring type_string;
if (!value.GetString(kTypeKey, &type_string))
@@ -167,16 +179,15 @@ bool BookmarkCodec::DecodeNode(BookmarkBarModel* model,
std::wstring url_string;
if (!value.GetString(kURLKey, &url_string))
return false;
- node->SetURL(GURL(url_string));
+ if (!node)
+ node = new BookmarkBarNode(model, GURL(url_string));
+ if (parent)
+ parent->Add(parent->GetChildCount(), node);
node->type_ = history::StarredEntry::URL;
} else {
- node->type_ = history::StarredEntry::USER_GROUP;
-
std::wstring last_modified_date;
if (!value.GetString(kDateModifiedKey, &last_modified_date))
return false;
- node->date_group_modified_ =
- Time::FromInternalValue(StringToInt64(last_modified_date));
Value* child_values;
if (!value.Get(kChildrenKey, &child_values))
@@ -185,13 +196,21 @@ bool BookmarkCodec::DecodeNode(BookmarkBarModel* model,
if (child_values->GetType() != Value::TYPE_LIST)
return false;
- if (!DecodeChildren(model, *static_cast<ListValue*>(child_values), node)) {
- // There was an error in building the children. Delete all the children.
- while (node->GetChildCount())
- delete node->Remove(node->GetChildCount() - 1);
+ if (!node)
+ node = new BookmarkBarNode(model, GURL());
+ node->type_ = history::StarredEntry::USER_GROUP;
+ node->date_group_modified_ =
+ Time::FromInternalValue(StringToInt64(last_modified_date));
+
+ if (parent)
+ parent->Add(parent->GetChildCount(), node);
+
+ if (!DecodeChildren(model, *static_cast<ListValue*>(child_values), node))
return false;
- }
}
+ node->SetTitle(title);
+ node->date_added_ =
+ Time::FromInternalValue(StringToInt64(date_added_string));
return true;
}
diff --git a/chrome/browser/bookmark_codec.h b/chrome/browser/bookmark_codec.h
index ffe51c2..912b8ae 100644
--- a/chrome/browser/bookmark_codec.h
+++ b/chrome/browser/bookmark_codec.h
@@ -49,9 +49,18 @@ class BookmarkCodec {
BookmarkCodec() {}
// Encodes the model to a JSON value. It's up to the caller to delete the
- // returned object.
+ // returned object. This is invoked to encode the contents of the bookmark bar
+ // model and is currently a convenience to invoking Encode that takes the
+ // bookmark bar node and other folder node.
Value* Encode(BookmarkBarModel* model);
+ // Encodes the bookmark bar and other folders returning the JSON value. It's
+ // up to the caller to delete the returned object.
+ // This method is public for use by StarredURLDatabase in migrating the
+ // bookmarks out of the database.
+ Value* Encode(BookmarkBarNode* bookmark_bar_node,
+ BookmarkBarNode* other_folder_node);
+
// Decodes the previously encoded value to the specified model. Returns true
// on success, false otherwise. If there is an error (such as unexpected
// version) all children are removed from the bookmark bar and other folder
@@ -69,9 +78,11 @@ class BookmarkCodec {
BookmarkBarNode* parent);
// Decodes the supplied node from the supplied value. Child nodes are
- // created appropriately by way of DecodeChildren.
+ // created appropriately by way of DecodeChildren. If node is NULL a new
+ // node is created and added to parent, otherwise node is used.
bool DecodeNode(BookmarkBarModel* model,
const DictionaryValue& value,
+ BookmarkBarNode* parent,
BookmarkBarNode* node);
DISALLOW_COPY_AND_ASSIGN(BookmarkCodec);
diff --git a/chrome/browser/bookmark_drag_data.cc b/chrome/browser/bookmark_drag_data.cc
index e4f4b22..8c14a2f 100644
--- a/chrome/browser/bookmark_drag_data.cc
+++ b/chrome/browser/bookmark_drag_data.cc
@@ -48,12 +48,10 @@ BookmarkDragData::BookmarkDragData(BookmarkBarNode* node)
: is_url(node->GetType() == history::StarredEntry::URL),
url(node->GetURL()),
title(node->GetTitle()),
- is_valid(true) {
- if (!is_url) {
- group_id_ = node->GetGroupID();
- DCHECK(group_id_);
+ is_valid(true),
+ id_(node->id()) {
+ if (!is_url)
AddChildren(node);
- }
}
void BookmarkDragData::Write(OSExchangeData* data) const {
@@ -89,8 +87,8 @@ bool BookmarkDragData::Read(const OSExchangeData& data) {
}
BookmarkBarNode* BookmarkDragData::GetNode(BookmarkBarModel* model) const {
- DCHECK(!is_url && group_id_ && is_valid);
- return model->GetNodeByGroupID(group_id_);
+ DCHECK(!is_url && id_ && is_valid);
+ return model->GetNodeByID(id_);
}
void BookmarkDragData::WriteToPickle(Pickle* pickle) const {
@@ -99,7 +97,7 @@ void BookmarkDragData::WriteToPickle(Pickle* pickle) const {
pickle->WriteString(url.spec());
pickle->WriteWString(title);
if (!is_url) {
- pickle->WriteInt64(group_id_);
+ pickle->WriteInt(id_);
pickle->WriteInt(static_cast<int>(children.size()));
for (std::vector<BookmarkDragData>::const_iterator i = children.begin();
i != children.end(); ++i) {
@@ -119,9 +117,9 @@ bool BookmarkDragData::ReadFromPickle(Pickle* pickle, void** iterator) {
}
url = GURL(url_spec);
if (!is_url) {
- group_id_ = 0;
+ id_ = 0;
children.clear();
- if (!pickle->ReadInt64(iterator, &group_id_))
+ if (!pickle->ReadInt(iterator, &id_))
return false;
int children_count;
if (!pickle->ReadInt(iterator, &children_count))
diff --git a/chrome/browser/bookmark_drag_data.h b/chrome/browser/bookmark_drag_data.h
index 054b922..feb54af 100644
--- a/chrome/browser/bookmark_drag_data.h
+++ b/chrome/browser/bookmark_drag_data.h
@@ -27,8 +27,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifndef CHROME_BROWSER_BOOKMARK_DRAG_DATA
-#define CHROME_BROWSER_BOOKMARK_DRAG_DATA
+#ifndef CHROME_BROWSER_BOOKMARK_DRAG_DATA_
+#define CHROME_BROWSER_BOOKMARK_DRAG_DATA_
#include <vector>
@@ -99,8 +99,8 @@ struct BookmarkDragData {
// Adds to children an entry for each child of node.
void AddChildren(BookmarkBarNode* node);
- // If we're a group, this is our id.
- history::UIStarID group_id_;
+ // ID (node->id()) of the node this BookmarkDragData was created from.
+ int id_;
};
-#endif // CHROME_BROWSER_BOOKMARK_DRAG_DATA
+#endif // CHROME_BROWSER_BOOKMARK_DRAG_DATA_
diff --git a/chrome/browser/bookmark_storage.cc b/chrome/browser/bookmark_storage.cc
index e1fed29..8c402b8 100644
--- a/chrome/browser/bookmark_storage.cc
+++ b/chrome/browser/bookmark_storage.cc
@@ -39,6 +39,7 @@
#include "chrome/browser/bookmark_bar_model.h"
#include "chrome/browser/bookmark_codec.h"
#include "chrome/browser/profile.h"
+#include "chrome/common/chrome_constants.h"
#include "chrome/common/json_value_serializer.h"
namespace {
@@ -50,90 +51,36 @@ const wchar_t* const kBackupExtension = L"bak";
// kBookmarksFileName.
const wchar_t* const kTmpExtension = L"tmp";
-// Name of file containing bookmarks.
-const wchar_t* const kBookmarksFileName = L"bookmarks.json";
-
// How often we save.
-static const int kSaveDelayMS = 2500;
-
-class BookmarkStorageBackend :
- public base::RefCountedThreadSafe<BookmarkStorageBackend> {
- public:
- explicit BookmarkStorageBackend(const std::wstring& path);
-
- // Writes the specified value to disk. This takes ownership of |value| and
- // deletes it when done.
- void Write(Value* value);
-
- // Reads the bookmarks from kBookmarksFileName. Notifies |service| with
- // the results on the specified MessageLoop.
- void Read(scoped_refptr<BookmarkStorage> service,
- MessageLoop* message_loop);
-
- private:
- // Path we read/write to.
- const std::wstring path_;
-
- DISALLOW_EVIL_CONSTRUCTORS(BookmarkStorageBackend);
-};
-
-BookmarkStorageBackend::BookmarkStorageBackend(const std::wstring& path)
- : path_(path) {
- // Make a backup of the current file.
- std::wstring backup_path = path;
- file_util::ReplaceExtension(&backup_path, kBackupExtension);
- file_util::CopyFile(path, backup_path);
-}
-
-void BookmarkStorageBackend::Write(Value* value) {
- DCHECK(value);
-
- // We own Value.
- scoped_ptr<Value> value_ref(value);
-
- std::string content;
- JSONWriter::Write(value, true, &content);
-
- // Write to a temp file, then rename.
- std::wstring tmp_file = path_;
- file_util::ReplaceExtension(&tmp_file, kTmpExtension);
-
- int bytes_written = file_util::WriteFile(tmp_file, content.c_str(),
- static_cast<int>(content.length()));
- if (bytes_written != -1) {
- MoveFileEx(tmp_file.c_str(), path_.c_str(),
- MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
- }
-}
-
-void BookmarkStorageBackend::Read(scoped_refptr<BookmarkStorage> service,
- MessageLoop* message_loop) {
- JSONFileValueSerializer serializer(path_);
- Value* root = NULL;
- serializer.Deserialize(&root);
-
- // BookmarkStorage takes ownership of root.
- message_loop->PostTask(FROM_HERE, NewRunnableMethod(
- service.get(), &BookmarkStorage::LoadedBookmarks, root));
-}
+const int kSaveDelayMS = 2500;
} // namespace
+// BookmarkStorage -------------------------------------------------------------
+
BookmarkStorage::BookmarkStorage(Profile* profile, BookmarkBarModel* model)
: model_(model),
#pragma warning(suppress: 4355) // Okay to pass "this" here.
- save_factory_(this) {
+ save_factory_(this),
+ backend_thread_(g_browser_process->file_thread()) {
std::wstring path = profile->GetPath();
- file_util::AppendToPath(&path, kBookmarksFileName);
- backend_ = new BookmarkStorageBackend(path);
+ file_util::AppendToPath(&path, chrome::kBookmarksFileName);
+ std::wstring tmp_history_path = profile->GetPath();
+ file_util::AppendToPath(&tmp_history_path, chrome::kHistoryBookmarksFileName);
+ backend_ = new BookmarkStorageBackend(path, tmp_history_path);
}
-void BookmarkStorage::LoadBookmarks() {
- backend_thread()->message_loop()->PostTask(
- FROM_HERE,
- NewRunnableMethod(backend_.get(), &BookmarkStorageBackend::Read,
- scoped_refptr<BookmarkStorage>(this),
- MessageLoop::current()));
+void BookmarkStorage::LoadBookmarks(bool load_from_history) {
+ if (!backend_thread()) {
+ backend_->Read(scoped_refptr<BookmarkStorage>(this), NULL,
+ load_from_history);
+ } else {
+ backend_thread()->message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(backend_.get(), &BookmarkStorageBackend::Read,
+ scoped_refptr<BookmarkStorage>(this),
+ MessageLoop::current(), load_from_history));
+ }
}
void BookmarkStorage::ScheduleSave() {
@@ -154,7 +101,9 @@ void BookmarkStorage::BookmarkModelDeleted() {
model_ = NULL;
}
-void BookmarkStorage::LoadedBookmarks(Value* root_value) {
+void BookmarkStorage::LoadedBookmarks(Value* root_value,
+ bool bookmark_file_exists,
+ bool loaded_from_history) {
scoped_ptr<Value> value_ref(root_value);
if (model_) {
@@ -162,8 +111,8 @@ void BookmarkStorage::LoadedBookmarks(Value* root_value) {
BookmarkCodec codec;
codec.Decode(model_, *root_value);
}
- // TODO(sky): bug 1256202 need to invoke a method back on the model telling
- // it all has loaded.
+ model_->OnBookmarkStorageLoadedBookmarks(bookmark_file_exists,
+ loaded_from_history);
}
}
@@ -178,8 +127,69 @@ void BookmarkStorage::SaveNow() {
BookmarkCodec codec;
Value* value = codec.Encode(model_);
// The backend deletes value in write.
- backend_thread()->message_loop()->PostTask(
- FROM_HERE,
- NewRunnableMethod(backend_.get(), &BookmarkStorageBackend::Write,
- value));
+ if (!backend_thread()) {
+ backend_->Write(value);
+ } else {
+ backend_thread()->message_loop()->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(backend_.get(), &BookmarkStorageBackend::Write,
+ value));
+ }
+}
+
+// BookmarkStorageBackend ------------------------------------------------------
+
+BookmarkStorageBackend::BookmarkStorageBackend(
+ const std::wstring& path,
+ const std::wstring& tmp_history_path)
+ : path_(path),
+ tmp_history_path_(tmp_history_path) {
+ // Make a backup of the current file.
+ std::wstring backup_path = path;
+ file_util::ReplaceExtension(&backup_path, kBackupExtension);
+ file_util::CopyFile(path, backup_path);
+}
+
+void BookmarkStorageBackend::Write(Value* value) {
+ DCHECK(value);
+
+ // We own Value.
+ scoped_ptr<Value> value_ref(value);
+
+ std::string content;
+ JSONWriter::Write(value, true, &content);
+
+ // Write to a temp file, then rename.
+ std::wstring tmp_file = path_;
+ file_util::ReplaceExtension(&tmp_file, kTmpExtension);
+
+ int bytes_written = file_util::WriteFile(tmp_file, content.c_str(),
+ static_cast<int>(content.length()));
+ if (bytes_written != -1) {
+ MoveFileEx(tmp_file.c_str(), path_.c_str(),
+ MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING);
+ // Nuke the history file so that we don't attempt to load from it again.
+ file_util::Delete(tmp_history_path_, false);
+ }
+}
+
+void BookmarkStorageBackend::Read(scoped_refptr<BookmarkStorage> service,
+ MessageLoop* message_loop,
+ bool load_from_history) {
+ const std::wstring& path = load_from_history ? tmp_history_path_ : path_;
+ bool bookmark_file_exists = file_util::PathExists(path);
+ Value* root = NULL;
+ if (bookmark_file_exists) {
+ JSONFileValueSerializer serializer(path);
+ serializer.Deserialize(&root);
+ }
+
+ // BookmarkStorage takes ownership of root.
+ if (message_loop) {
+ message_loop->PostTask(FROM_HERE, NewRunnableMethod(
+ service.get(), &BookmarkStorage::LoadedBookmarks, root,
+ bookmark_file_exists, load_from_history));
+ } else {
+ service->LoadedBookmarks(root, bookmark_file_exists, load_from_history);
+ }
}
diff --git a/chrome/browser/bookmark_storage.h b/chrome/browser/bookmark_storage.h
index 8ba00d0..5792c00 100644
--- a/chrome/browser/bookmark_storage.h
+++ b/chrome/browser/bookmark_storage.h
@@ -27,17 +27,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// BookmarkService handles reading/write the bookmark bar model. The
-// BookmarkBarModel uses the BookmarkService to load bookmarks from
-// disk, as well as notifying the BookmarkService every time the model
-// changes.
-//
-// Internally BookmarkService uses BookmarkCoded to do the actual read/write.
-
-// NOTE: This class is currently unsed. The plan is to move bookmarks
-// out of the history db using this class and BookmarksCodec instead
-// (bug 1256202).
-
#ifndef CHROME_BROWSER_BOOKMARK_STORAGE_H_
#define CHROME_BROWSER_BOOKMARK_STORAGE_H_
@@ -49,9 +38,12 @@ class BookmarkBarModel;
class Profile;
class Value;
-namespace {
-class BookmarkStorageBackend;
-}
+// BookmarkStorage handles reading/write the bookmark bar model. The
+// BookmarkBarModel uses the BookmarkStorage to load bookmarks from
+// disk, as well as notifying the BookmarkStorage every time the model
+// changes.
+//
+// Internally BookmarkStorage uses BookmarkCodec to do the actual read/write.
class BookmarkStorage : public base::RefCountedThreadSafe<BookmarkStorage> {
friend class BookmarkStorageBackend;
@@ -60,8 +52,10 @@ class BookmarkStorage : public base::RefCountedThreadSafe<BookmarkStorage> {
// Creates a BookmarkStorage for the specified model
BookmarkStorage(Profile* profile, BookmarkBarModel* model);
- // Loads the bookmarks into the model, notifying the model when done.
- void LoadBookmarks();
+ // Loads the bookmarks into the model, notifying the model when done. If
+ // load_from_history is true, the bookmarks are loaded from the file written
+ // by history (StarredURLDatabase).
+ void LoadBookmarks(bool load_from_history);
// Schedules saving the bookmark bar model to disk.
void ScheduleSave();
@@ -72,13 +66,15 @@ class BookmarkStorage : public base::RefCountedThreadSafe<BookmarkStorage> {
private:
// Callback from backend with the results of the bookmark file.
- void LoadedBookmarks(Value* root_value);
+ void LoadedBookmarks(Value* root_value,
+ bool bookmark_file_exists,
+ bool loaded_from_history);
// Schedules a save on the backend thread.
void SaveNow();
// Returns the thread the backend is run on.
- Thread* backend_thread() { return g_browser_process->file_thread(); }
+ Thread* backend_thread() const { return backend_thread_; }
// The model. The model is NULL once BookmarkModelDeleted has been invoked.
BookmarkBarModel* model_;
@@ -89,7 +85,38 @@ class BookmarkStorage : public base::RefCountedThreadSafe<BookmarkStorage> {
// The backend handles actual reading/writing to disk.
scoped_refptr<BookmarkStorageBackend> backend_;
+ // Thread read/writing is run on. This comes from the profile, and is null
+ // during testing.
+ Thread* backend_thread_;
+
DISALLOW_COPY_AND_ASSIGN(BookmarkStorage);
};
+// Used to save the bookmarks on the file thread.
+class BookmarkStorageBackend :
+ public base::RefCountedThreadSafe<BookmarkStorageBackend> {
+ public:
+ explicit BookmarkStorageBackend(const std::wstring& path,
+ const std::wstring& tmp_histor_path);
+
+ // Writes the specified value to disk. This takes ownership of |value| and
+ // deletes it when done.
+ void Write(Value* value);
+
+ // Reads the bookmarks from kBookmarksFileName. Notifies |service| with
+ // the results on the specified MessageLoop.
+ void Read(scoped_refptr<BookmarkStorage> service,
+ MessageLoop* message_loop,
+ bool load_from_history);
+
+ private:
+ // Path we read/write to.
+ const std::wstring path_;
+
+ // Path bookmarks are read from if asked to load from history file.
+ const std::wstring tmp_history_path_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(BookmarkStorageBackend);
+};
+
#endif // CHROME_BROWSER_BOOKMARK_STORAGE_H_
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index 5fee2a1..0747b6f 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -818,6 +818,14 @@
>
</File>
<File
+ RelativePath=".\bookmark_codec.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\bookmark_codec.h"
+ >
+ </File>
+ <File
RelativePath=".\bookmark_drag_data.cc"
>
</File>
@@ -825,6 +833,14 @@
RelativePath=".\bookmark_drag_data.h"
>
</File>
+ <File
+ RelativePath=".\bookmark_storage.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\bookmark_storage.h"
+ >
+ </File>
</Filter>
<Filter
Name="Tab Contents"
diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc
index ef36f49..58ce89d 100644
--- a/chrome/browser/dom_ui/new_tab_ui.cc
+++ b/chrome/browser/dom_ui/new_tab_ui.cc
@@ -518,37 +518,63 @@ void TemplateURLHandler::OnTemplateURLModelChanged() {
}
RecentlyBookmarkedHandler::RecentlyBookmarkedHandler(DOMUIHost* dom_ui_host)
- : dom_ui_host_(dom_ui_host) {
+ : dom_ui_host_(dom_ui_host),
+ model_(NULL) {
dom_ui_host->RegisterMessageCallback("getRecentlyBookmarked",
NewCallback(this,
&RecentlyBookmarkedHandler::HandleGetRecentlyBookmarked));
}
+RecentlyBookmarkedHandler::~RecentlyBookmarkedHandler() {
+ if (model_)
+ model_->RemoveObserver(this);
+}
+
void RecentlyBookmarkedHandler::HandleGetRecentlyBookmarked(const Value*) {
- HistoryService* hs =
- dom_ui_host_->profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
- if (hs) {
- HistoryService::Handle handle = hs->GetMostRecentStarredEntries(
- kRecentBookmarks,
- &cancelable_consumer_,
- NewCallback(this,
- &RecentlyBookmarkedHandler::OnMostRecentStarredEntries));
+ if (!model_) {
+ model_ = dom_ui_host_->profile()->GetBookmarkBarModel();
+ model_->AddObserver(this);
}
+ // If the model is loaded, synchronously send the bookmarks down. Otherwise
+ // when the model loads we'll send the bookmarks down.
+ if (model_->IsLoaded())
+ SendBookmarksToPage();
}
-void RecentlyBookmarkedHandler::OnMostRecentStarredEntries(
- HistoryService::Handle request_handle,
- std::vector<history::StarredEntry>* entries) {
+void RecentlyBookmarkedHandler::SendBookmarksToPage() {
+ std::vector<BookmarkBarNode*> recently_bookmarked;
+ model_->GetMostRecentlyAddedEntries(kRecentBookmarks, &recently_bookmarked);
ListValue list_value;
- for (size_t i = 0; i < entries->size(); ++i) {
- const history::StarredEntry& entry = (*entries)[i];
+ for (size_t i = 0; i < recently_bookmarked.size(); ++i) {
+ BookmarkBarNode* node = recently_bookmarked[i];
DictionaryValue* entry_value = new DictionaryValue;
- SetURLAndTitle(entry_value, entry.title, entry.url);
+ SetURLAndTitle(entry_value, node->GetTitle(), node->GetURL());
list_value.Append(entry_value);
}
dom_ui_host_->CallJavascriptFunction(L"recentlyBookmarked", list_value);
}
+void RecentlyBookmarkedHandler::Loaded(BookmarkBarModel* model) {
+ SendBookmarksToPage();
+}
+
+void RecentlyBookmarkedHandler::BookmarkNodeAdded(BookmarkBarModel* model,
+ BookmarkBarNode* parent,
+ int index) {
+ SendBookmarksToPage();
+}
+
+void RecentlyBookmarkedHandler::BookmarkNodeRemoved(BookmarkBarModel* model,
+ BookmarkBarNode* parent,
+ int index) {
+ SendBookmarksToPage();
+}
+
+void RecentlyBookmarkedHandler::BookmarkNodeChanged(BookmarkBarModel* model,
+ BookmarkBarNode* node) {
+ SendBookmarksToPage();
+}
+
RecentlyClosedTabsHandler::RecentlyClosedTabsHandler(DOMUIHost* dom_ui_host)
: dom_ui_host_(dom_ui_host),
tab_restore_service_(NULL),
diff --git a/chrome/browser/dom_ui/new_tab_ui.h b/chrome/browser/dom_ui/new_tab_ui.h
index 71a4f50..944fa88 100644
--- a/chrome/browser/dom_ui/new_tab_ui.h
+++ b/chrome/browser/dom_ui/new_tab_ui.h
@@ -30,6 +30,7 @@
#ifndef CHROME_BROWSER_DOM_UI_NEW_TAB_UI_H__
#define CHROME_BROWSER_DOM_UI_NEW_TAB_UI_H__
+#include "chrome/browser/bookmark_bar_model.h"
#include "chrome/browser/dom_ui/dom_ui_host.h"
#include "chrome/browser/dom_ui/chrome_url_data_manager.h"
#include "chrome/browser/history/history.h"
@@ -202,9 +203,11 @@ class TemplateURLHandler : public DOMMessageHandler,
DISALLOW_EVIL_CONSTRUCTORS(TemplateURLHandler);
};
-class RecentlyBookmarkedHandler : public DOMMessageHandler {
+class RecentlyBookmarkedHandler : public DOMMessageHandler,
+ public BookmarkBarModelObserver {
public:
explicit RecentlyBookmarkedHandler(DOMUIHost* dom_ui_host);
+ ~RecentlyBookmarkedHandler();
// Callback which navigates to the bookmarks page.
void HandleShowBookmarkPage(const Value*);
@@ -213,13 +216,32 @@ class RecentlyBookmarkedHandler : public DOMMessageHandler {
// It takes no arguments.
void HandleGetRecentlyBookmarked(const Value*);
- void OnMostRecentStarredEntries(
- HistoryService::Handle request_handle,
- std::vector<history::StarredEntry>* entries);
-
private:
+ void SendBookmarksToPage();
+
+ // BookmarkBarModelObserver methods. These invoke SendBookmarksToPage.
+ virtual void Loaded(BookmarkBarModel* model);
+ 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);
+
+ // These two won't effect what is shown, so they do nothing.
+ virtual void BookmarkNodeMoved(BookmarkBarModel* model,
+ BookmarkBarNode* old_parent,
+ int old_index,
+ BookmarkBarNode* new_parent,
+ int new_index) {}
+ virtual void BookmarkNodeFavIconLoaded(BookmarkBarModel* model,
+ BookmarkBarNode* node) {}
+
DOMUIHost* dom_ui_host_;
- CancelableRequestConsumerT<int, 0> cancelable_consumer_;
+ // The model we're getting bookmarks from. The model is owned by the Profile.
+ BookmarkBarModel* model_;
DISALLOW_EVIL_CONSTRUCTORS(RecentlyBookmarkedHandler);
};
diff --git a/chrome/browser/history/archived_database.cc b/chrome/browser/history/archived_database.cc
index 19f6436..40ba38b 100644
--- a/chrome/browser/history/archived_database.cc
+++ b/chrome/browser/history/archived_database.cc
@@ -34,7 +34,7 @@ namespace history {
namespace {
-static const int kDatabaseVersion = 1;
+static const int kCurrentVersionNumber = 2;
} // namespace
@@ -73,15 +73,8 @@ bool ArchivedDatabase::Init(const std::wstring& file_name) {
BeginTransaction();
// Version check.
- if (!meta_table_.Init(std::string(), kDatabaseVersion, db_))
+ if (!meta_table_.Init(std::string(), kCurrentVersionNumber, db_))
return false;
- if (meta_table_.GetCompatibleVersionNumber() > kDatabaseVersion) {
- // We ignore this error and just run without the database. Normally, if
- // the user is running two versions, the main history DB will give a
- // warning about a version from the future.
- LOG(WARNING) << "Archived database is a future version.";
- return false;
- }
// Create the tables.
if (!CreateURLTable(false) || !InitVisitTable() ||
@@ -89,6 +82,9 @@ bool ArchivedDatabase::Init(const std::wstring& file_name) {
return false;
CreateMainURLIndex();
+ if (EnsureCurrentVersion() != INIT_OK)
+ return false;
+
// Succeeded: keep the DB open by detaching the auto-closer.
scoper.Detach();
db_closer_.Attach(&db_, &statement_cache_);
@@ -123,4 +119,36 @@ SqliteStatementCache& ArchivedDatabase::GetStatementCache() {
return *statement_cache_;
}
+// Migration -------------------------------------------------------------------
+
+InitStatus ArchivedDatabase::EnsureCurrentVersion() {
+ // We can't read databases newer than we were designed for.
+ if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber)
+ return INIT_TOO_NEW;
+
+ // NOTICE: If you are changing structures for things shared with the archived
+ // history file like URLs, visits, or downloads, that will need migration as
+ // well. Instead of putting such migration code in this class, it should be
+ // in the corresponding file (url_database.cc, etc.) and called from here and
+ // from the archived_database.cc.
+
+ // When the version is too old, we just try to continue anyway, there should
+ // not be a released product that makes a database too old for us to handle.
+ int cur_version = meta_table_.GetVersionNumber();
+
+ // Put migration code here
+
+ if (cur_version == 1) {
+ if (!DropStarredIDFromURLs())
+ return INIT_FAILURE;
+ cur_version = 2;
+ meta_table_.SetVersionNumber(cur_version);
+ meta_table_.SetCompatibleVersionNumber(cur_version);
+ }
+
+ LOG_IF(WARNING, cur_version < kCurrentVersionNumber) <<
+ "Archived database version " << cur_version << " is too old to handle.";
+
+ return INIT_OK;
+}
} // namespace history
diff --git a/chrome/browser/history/archived_database.h b/chrome/browser/history/archived_database.h
index 985dd35..d6617ff 100644
--- a/chrome/browser/history/archived_database.h
+++ b/chrome/browser/history/archived_database.h
@@ -67,6 +67,15 @@ class ArchivedDatabase : public URLDatabase,
virtual sqlite3* GetDB();
virtual SqliteStatementCache& GetStatementCache();
+ // Makes sure the version is up-to-date, updating if necessary. If the
+ // database is too old to migrate, the user will be notified. In this case, or
+ // for other errors, false will be returned. True means it is up-to-date and
+ // ready for use.
+ //
+ // This assumes it is called from the init function inside a transaction. It
+ // may commit the transaction and start a new one if migration requires it.
+ InitStatus EnsureCurrentVersion();
+
// The database.
//
// The close scoper will free the database and delete the statement cache in
diff --git a/chrome/browser/history/expire_history_backend.cc b/chrome/browser/history/expire_history_backend.cc
index ba42e07..e8065ff 100644
--- a/chrome/browser/history/expire_history_backend.cc
+++ b/chrome/browser/history/expire_history_backend.cc
@@ -124,8 +124,8 @@ void ExpireHistoryBackend::DeleteURL(const GURL& url) {
text_db_->DeleteURLFromUncommitted(url);
// Collect all the visits and delete them. Note that we don't give up if
- // there are no visits, since the URL could still have an entry (for example,
- // if it's starred) that we should delete.
+ // there are no visits, since the URL could still have an entry that we should
+ // delete.
// TODO(brettw): bug 1171148: We should also delete from the archived DB.
VisitVector visits;
main_db_->GetVisitsForURL(url_row.id(), &visits);
@@ -205,14 +205,6 @@ void ExpireHistoryBackend::DeleteFaviconsIfPossible(
void ExpireHistoryBackend::BroadcastDeleteNotifications(
DeleteDependencies* dependencies) {
- // Broadcast the "unstarred" notification.
- if (!dependencies->unstarred_urls.empty()) {
- URLsStarredDetails* unstarred_details = new URLsStarredDetails(false);
- unstarred_details->changed_urls.swap(dependencies->unstarred_urls);
- unstarred_details->star_entries.swap(dependencies->unstarred_entries);
- delegate_->BroadcastNotifications(NOTIFY_URLS_STARRED, unstarred_details);
- }
-
if (!dependencies->deleted_urls.empty()) {
// Broadcast the URL deleted notification. Note that we also broadcast when
// we were requested to delete everything even if that was a NOP, since
@@ -284,15 +276,6 @@ void ExpireHistoryBackend::DeleteOneURL(
thumb_db_->DeleteThumbnail(url_row.id());
main_db_->DeleteSegmentForURL(url_row.id());
- // The starred table may need to have its corresponding item deleted.
- if (url_row.star_id()) {
- // Note that this will update the URLRow's starred field, but our variable
- // won't be updated correspondingly.
- main_db_->DeleteStarredEntry(url_row.star_id(),
- &dependencies->unstarred_urls,
- &dependencies->unstarred_entries);
- }
-
// Collect shared information.
if (url_row.favicon_id())
dependencies->affected_favicons.insert(url_row.favicon_id());
@@ -362,8 +345,8 @@ void ExpireHistoryBackend::ExpireURLsForVisits(
else
url_row.set_last_visit(Time());
- // Don't delete starred URLs or ones with visits still in the DB.
- if (url_row.starred() || !url_row.last_visit().is_null()) {
+ // Don't delete URLs with visits still in the DB.
+ if (!url_row.last_visit().is_null()) {
// We're not deleting the URL, update its counts when we're deleting those
// visits.
// NOTE: The calls to std::max() below are a backstop, but they should
diff --git a/chrome/browser/history/expire_history_backend.h b/chrome/browser/history/expire_history_backend.h
index 4862f9a..0ed5676 100644
--- a/chrome/browser/history/expire_history_backend.h
+++ b/chrome/browser/history/expire_history_backend.h
@@ -81,8 +81,7 @@ class ExpireHistoryBackend {
// will continue until the object is deleted.
void StartArchivingOldStuff(TimeDelta expiration_threshold);
- // Deletes everything associated with a URL, regardless of whether it is
- // starred or not.
+ // Deletes everything associated with a URL.
void DeleteURL(const GURL& url);
// Removes all visits in the given time range, updating the URLs accordingly.
@@ -128,10 +127,6 @@ class ExpireHistoryBackend {
// that we will need to check when the delete operations are complete.
std::set<FavIconID> affected_favicons;
- // URLs that were unstarred as a result of the delete.
- std::set<GURL> unstarred_urls;
- std::vector<StarredEntry> unstarred_entries;
-
// Tracks the set of databases that have changed so we can optimize when
// when we're done.
TextDatabaseManager::ChangeSet text_db_changes;
diff --git a/chrome/browser/history/expire_history_backend_unittest.cc b/chrome/browser/history/expire_history_backend_unittest.cc
index 0cd12da..28d90ab 100644
--- a/chrome/browser/history/expire_history_backend_unittest.cc
+++ b/chrome/browser/history/expire_history_backend_unittest.cc
@@ -111,7 +111,7 @@ class ExpireHistoryTest : public testing::Test,
std::wstring history_name(dir_);
file_util::AppendToPath(&history_name, L"History");
main_db_.reset(new HistoryDatabase);
- if (main_db_->Init(history_name) != INIT_OK)
+ if (main_db_->Init(history_name, std::wstring()) != INIT_OK)
main_db_.reset();
std::wstring archived_name(dir_);
@@ -460,32 +460,6 @@ TEST_F(ExpireHistoryTest, DeleteURLWithoutFavicon) {
EXPECT_TRUE(HasFavIcon(last_row.favicon_id()));
}
-// DeletdeURL should delete URLs that are starred.
-TEST_F(ExpireHistoryTest, DeleteStarredURL) {
- URLID url_ids[3];
- Time visit_times[4];
- AddExampleData(url_ids, visit_times);
-
- URLRow url_row;
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row));
-
- // Star the last URL.
- StarredEntry starred;
- starred.type = StarredEntry::URL;
- starred.url = url_row.url();
- starred.url_id = url_row.id();
- starred.parent_group_id = HistoryService::kBookmarkBarID;
- ASSERT_TRUE(main_db_->CreateStarredEntry(&starred));
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row));
-
- // Now delete it, this should delete it even though it's starred.
- expirer_.DeleteURL(url_row.url());
-
- // All the normal data + the favicon should be gone.
- EnsureURLInfoGone(url_row);
- EXPECT_FALSE(HasFavIcon(url_row.favicon_id()));
-}
-
// Expires all URLs more recent than a given time, with no starred items.
// Our time threshold is such that one URL should be updated (we delete one of
// the two visits) and one is deleted.
@@ -540,62 +514,6 @@ TEST_F(ExpireHistoryTest, FlushRecentURLsUnstarred) {
EXPECT_FALSE(HasFavIcon(url_row2.favicon_id()));
}
-// Expire a starred URL, it shouldn't get deleted and its visit counts should
-// be updated properly.
-TEST_F(ExpireHistoryTest, FlushRecentURLsStarred) {
- URLID url_ids[3];
- Time visit_times[4];
- AddExampleData(url_ids, visit_times);
-
- URLRow url_row1, url_row2;
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &url_row1));
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row2));
-
- // Star the last two URLs.
- StarredEntry starred1;
- starred1.type = StarredEntry::URL;
- starred1.url = url_row1.url();
- starred1.url_id = url_row1.id();
- starred1.parent_group_id = HistoryService::kBookmarkBarID;
- ASSERT_TRUE(main_db_->CreateStarredEntry(&starred1));
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &url_row1));
-
- StarredEntry starred2;
- starred2.type = StarredEntry::URL;
- starred2.url = url_row2.url();
- starred2.url_id = url_row2.id();
- starred2.parent_group_id = HistoryService::kBookmarkBarID;
- ASSERT_TRUE(main_db_->CreateStarredEntry(&starred2));
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row2));
-
- // This should delete the last two visits.
- expirer_.ExpireHistoryBetween(visit_times[2], Time());
-
- // The URL rows should still exist.
- URLRow new_url_row1, new_url_row2;
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &new_url_row1));
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &new_url_row2));
-
- // The visit times should be updated.
- EXPECT_TRUE(new_url_row1.last_visit() == visit_times[1]);
- EXPECT_TRUE(new_url_row2.last_visit().is_null()); // No last visit time.
-
- // Visit counts should be updated.
- EXPECT_EQ(0, new_url_row1.typed_count());
- EXPECT_EQ(1, new_url_row1.visit_count());
- EXPECT_EQ(0, new_url_row2.typed_count());
- EXPECT_EQ(0, new_url_row2.visit_count());
-
- // Thumbnails and favicons should still exist. Note that we keep thumbnails
- // that may have been updated since the time threshold. Since the URL still
- // exists in history, this should not be a privacy problem, we only update
- // the visit counts in this case for consistency anyway.
- EXPECT_TRUE(HasFavIcon(new_url_row1.favicon_id()));
- EXPECT_TRUE(HasThumbnail(new_url_row1.id()));
- EXPECT_TRUE(HasFavIcon(new_url_row2.favicon_id()));
- EXPECT_TRUE(HasThumbnail(new_url_row2.id()));
-}
-
TEST_F(ExpireHistoryTest, ArchiveHistoryBeforeUnstarred) {
URLID url_ids[3];
Time visit_times[4];
@@ -634,53 +552,6 @@ TEST_F(ExpireHistoryTest, ArchiveHistoryBeforeUnstarred) {
EXPECT_EQ(1, archived_visits.size());
}
-TEST_F(ExpireHistoryTest, ArchiveHistoryBeforeStarred) {
- URLID url_ids[3];
- Time visit_times[4];
- AddExampleData(url_ids, visit_times);
-
- URLRow url_row0, url_row1;
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[0], &url_row0));
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &url_row1));
-
- // Star the URLs. We use fake star IDs here, but that doesn't matter.
- url_row0.set_star_id(1);
- main_db_->UpdateURLRow(url_row0.id(), url_row0);
- url_row1.set_star_id(2);
- main_db_->UpdateURLRow(url_row1.id(), url_row1);
-
- // Now archive the first three visits (first two URLs). The first two visits
- // should be, the thirddeleted, but the URL records should not.
- expirer_.ArchiveHistoryBefore(visit_times[2]);
-
- // The first URL should have its visit deleted, but it should still be present
- // in the main DB and not in the archived one since it is starred.
- URLRow temp_row;
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[0], &temp_row));
- // Note that the ID is different in the archived DB, so look up by URL.
- EXPECT_FALSE(archived_db_->GetRowForURL(temp_row.url(), NULL));
- VisitVector visits;
- main_db_->GetVisitsForURL(temp_row.id(), &visits);
- EXPECT_EQ(0, visits.size());
-
- // The second URL should have its first visit deleted and its second visit
- // archived. It should be present in both the main DB (because it's starred)
- // and the archived DB (for the archived visit).
- ASSERT_TRUE(main_db_->GetURLRow(url_ids[1], &temp_row));
- main_db_->GetVisitsForURL(temp_row.id(), &visits);
- EXPECT_EQ(0, visits.size());
-
- // Note that the ID is different in the archived DB, so look up by URL.
- ASSERT_TRUE(archived_db_->GetRowForURL(temp_row.url(), &temp_row));
- archived_db_->GetVisitsForURL(temp_row.id(), &visits);
- ASSERT_EQ(1, visits.size());
- EXPECT_TRUE(visit_times[2] == visits[0].visit_time);
-
- // The third URL should be unchanged.
- EXPECT_TRUE(main_db_->GetURLRow(url_ids[2], &temp_row));
- EXPECT_FALSE(archived_db_->GetRowForURL(temp_row.url(), NULL));
-}
-
// Tests the return values from ArchiveSomeOldHistory. The rest of the
// functionality of this function is tested by the ArchiveHistoryBefore*
// tests which use this function internally.
diff --git a/chrome/browser/history/history.cc b/chrome/browser/history/history.cc
index d4e6879..bebc348 100644
--- a/chrome/browser/history/history.cc
+++ b/chrome/browser/history/history.cc
@@ -241,6 +241,13 @@ HistoryService::Handle HistoryService::ScheduleDBTask(
request);
}
+HistoryService::Handle HistoryService::ScheduleEmptyCallback(
+ CancelableRequestConsumerBase* consumer,
+ EmptyHistoryCallback* callback) {
+ return Schedule(PRIORITY_UI, &HistoryBackend::ProcessEmptyRequest,
+ consumer, new history::EmptyHistoryRequest(callback));
+}
+
HistoryService::Handle HistoryService::QuerySegmentUsageSince(
CancelableRequestConsumerBase* consumer,
const Time from_time,
@@ -435,55 +442,6 @@ void HistoryService::SetImportedFavicons(
&HistoryBackend::SetImportedFavicons, favicon_usage);
}
-HistoryService::Handle HistoryService::GetAllStarredEntries(
- CancelableRequestConsumerBase* consumer,
- GetStarredEntriesCallback* callback) {
- return Schedule(PRIORITY_UI, &HistoryBackend::GetAllStarredEntries,
- consumer,
- new history::GetStarredEntriesRequest(callback));
-}
-
-void HistoryService::UpdateStarredEntry(const history::StarredEntry& entry) {
- ScheduleAndForget(PRIORITY_UI, &HistoryBackend::UpdateStarredEntry, entry);
-}
-
-HistoryService::Handle HistoryService::CreateStarredEntry(
- const history::StarredEntry& entry,
- CancelableRequestConsumerBase* consumer,
- CreateStarredEntryCallback* callback) {
- DCHECK(entry.type != history::StarredEntry::BOOKMARK_BAR &&
- entry.type != history::StarredEntry::OTHER);
- if (!consumer) {
- ScheduleTask(PRIORITY_UI,
- NewRunnableMethod(history_backend_.get(),
- &HistoryBackend::CreateStarredEntry,
- scoped_refptr<history::CreateStarredEntryRequest>(),
- entry));
- return 0;
- }
- return Schedule(PRIORITY_UI, &HistoryBackend::CreateStarredEntry, consumer,
- new history::CreateStarredEntryRequest(callback), entry);
-}
-
-void HistoryService::DeleteStarredGroup(history::UIStarID group_id) {
- ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteStarredGroup,
- group_id);
-}
-
-void HistoryService::DeleteStarredURL(const GURL& url) {
- ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::DeleteStarredURL, url);
-}
-
-HistoryService::Handle HistoryService::GetMostRecentStarredEntries(
- int max_count,
- CancelableRequestConsumerBase* consumer,
- GetMostRecentStarredEntriesCallback* callback) {
- return Schedule(PRIORITY_UI, &HistoryBackend::GetMostRecentStarredEntries,
- consumer,
- new history::GetMostRecentStarredEntriesRequest(callback),
- max_count);
-}
-
void HistoryService::IterateURLs(URLEnumerator* enumerator) {
ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::IterateURLs, enumerator);
}
diff --git a/chrome/browser/history/history.h b/chrome/browser/history/history.h
index 9dca73a..3db1e23 100644
--- a/chrome/browser/history/history.h
+++ b/chrome/browser/history/history.h
@@ -393,29 +393,6 @@ class HistoryService : public CancelableRequestProvider,
void SetImportedFavicons(
const std::vector<history::ImportedFavIconUsage>& favicon_usage);
- // Starring ------------------------------------------------------------------
-
- // Starring mutation methods are private, go through the BookmarkBarModel
- // instead.
- //
- // The typedefs are public to allow template magic to work.
-
- typedef Callback2<Handle, std::vector<history::StarredEntry>* >::Type
- GetStarredEntriesCallback;
-
- typedef Callback2<Handle, history::StarID>::Type CreateStarredEntryCallback;
-
- typedef Callback2<Handle, std::vector<history::StarredEntry>* >::Type
- GetMostRecentStarredEntriesCallback;
-
- // Fetches up to max_count starred entries of type URL.
- // The results are ordered by date added in descending order (most recent
- // first).
- Handle GetMostRecentStarredEntries(
- int max_count,
- CancelableRequestConsumerBase* consumer,
- GetMostRecentStarredEntriesCallback* callback);
-
// Database management operations --------------------------------------------
// Delete all the information related to a single url.
@@ -544,6 +521,13 @@ class HistoryService : public CancelableRequestProvider,
Handle ScheduleDBTask(HistoryDBTask* task,
CancelableRequestConsumerBase* consumer);
+ typedef Callback1<Handle>::Type EmptyHistoryCallback;
+
+ // Schedules a task that does nothing on the backend. This can be used to get
+ // notification when then history backend is done processing requests.
+ Handle ScheduleEmptyCallback(CancelableRequestConsumerBase* consumer,
+ EmptyHistoryCallback* callback);
+
// Testing -------------------------------------------------------------------
// Designed for unit tests, this passes the given task on to the history
@@ -597,51 +581,6 @@ class HistoryService : public CancelableRequestProvider,
friend class HistoryOperation;
friend class HistoryURLProviderTest;
- // Starring ------------------------------------------------------------------
-
- // These are private as they should only be invoked from the bookmark bar
- // model.
-
- // Fetches all the starred entries (both groups and entries).
- Handle GetAllStarredEntries(
- CancelableRequestConsumerBase* consumer,
- GetStarredEntriesCallback* callback);
-
- // Updates the title, parent and visual order of the specified entry. The key
- // used to identify the entry is NOT entry.id, rather it is the url (if the
- // type is URL), or the group_id (if the type is other than URL).
- //
- // This can NOT be used to change the type of an entry.
- //
- // After updating the entry, NOTIFY_STAR_ENTRY_CHANGED is sent.
- void UpdateStarredEntry(const history::StarredEntry& entry);
-
- // Creates a starred entry at the specified position. This can be used
- // for creating groups and nodes.
- //
- // If the entry is a URL and the URL is already starred, this behaves the
- // same as invoking UpdateStarredEntry. If the entry is a URL and the URL is
- // not starred, the URL is starred appropriately.
- //
- // This honors the title, parent_group_id, visual_order and url (for URL
- // nodes) of the specified entry. All other attributes are ignored.
- //
- // NOTE: consumer and callback may be null, in which case the request
- // isn't cancelable and 0 is returned.
- Handle CreateStarredEntry(const history::StarredEntry& entry,
- CancelableRequestConsumerBase* consumer,
- CreateStarredEntryCallback* callback);
-
- // Deletes the specified starred group. All children groups are deleted and
- // starred descendants unstarred. If successful, this sends out the
- // notification NOTIFY_URLS_STARRED. To delete a starred URL, do
- // DeletedStarredEntry(id).
- void DeleteStarredGroup(history::UIStarID group_id);
-
- // Deletes the specified starred URL. If successful, this sends out the
- // notification NOTIFY_URLS_STARRED.
- void DeleteStarredURL(const GURL& url);
-
// Implementation of NotificationObserver.
virtual void Observe(NotificationType type,
const NotificationSource& source,
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index d9ef224..88e40ed 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -268,10 +268,13 @@ void HistoryBackend::Init() {
file_util::AppendToPath(&history_name, chrome::kHistoryFilename);
std::wstring thumbnail_name = GetThumbnailFileName();
std::wstring archived_name = GetArchivedFileName();
+ std::wstring tmp_bookmarks_file = history_dir_;
+ file_util::AppendToPath(&tmp_bookmarks_file,
+ chrome::kHistoryBookmarksFileName);
// History database.
db_.reset(new HistoryDatabase());
- switch (db_->Init(history_name)) {
+ switch (db_->Init(history_name, tmp_bookmarks_file)) {
case INIT_OK:
break;
case INIT_FAILURE:
@@ -995,16 +998,6 @@ void HistoryBackend::QueryHistory(scoped_refptr<QueryHistoryRequest> request,
if (db_.get()) {
if (text_query.empty()) {
- if (options.begin_time.is_null() && options.end_time.is_null() &&
- options.only_starred && options.max_count == 0) {
- DLOG(WARNING) << "Querying for all bookmarks. You should probably use "
- "the dedicated starring functions which will also report unvisited "
- "bookmarks and will be faster.";
- // If this case is needed and the starring functions aren't right, we
- // can optimize the case where we're just querying for starred URLs
- // and remove the warning.
- }
-
// Basic history query for the main database.
QueryHistoryBasic(db_.get(), db_.get(), options, &request->value);
@@ -1060,14 +1053,8 @@ void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db,
// catch any interesting stuff. This will update it if it exists in the
// main DB, and do nothing otherwise.
db_->GetRowForURL(url_result.url(), &url_result);
- } else {
- // URLs not in the main DB can't be starred, reset this just in case.
- url_result.set_star_id(0);
}
- if (!url_result.starred() && options.only_starred)
- continue; // Want non-starred items filtered out.
-
url_result.set_visit_time(visit.visit_time);
// We don't set any of the query-specific parts of the URLResult, since
@@ -1076,62 +1063,6 @@ void HistoryBackend::QueryHistoryBasic(URLDatabase* url_db,
}
}
-void HistoryBackend::QueryStarredEntriesByText(
- URLQuerier* querier,
- const std::wstring& text_query,
- const QueryOptions& options,
- QueryResults* results) {
- // Collect our prepends so we can bulk add them at the end. It is more
- // efficient to bluk prepend the URLs than to do one at a time.
- QueryResults our_results;
-
- // We can use only the main DB (not archived) for this operation since we know
- // that all currently starred URLs will be in the main DB.
- std::set<URLID> ids;
- db_->GetURLsForTitlesMatching(text_query, &ids);
-
- VisitRow visit;
- PageVisit page_visit;
- URLResult url_result;
- for (std::set<URLID>::iterator i = ids.begin(); i != ids.end(); ++i) {
- // Turn the ID (associated with the main DB) into a visit row.
- if (!db_->GetURLRow(*i, &url_result))
- continue; // Not found, some crazy error.
-
- // Make sure we haven't already reported this URL and don't add it if so.
- if (querier->HasURL(url_result.url()))
- continue;
-
- // Consistency check, all URLs should be valid and starred.
- if (!url_result.url().is_valid() || !url_result.starred())
- continue;
-
- db_->GetStarredEntry(url_result.star_id(), &url_result.starred_entry_);
-
- // Use the last visit time as the visit time for this result.
- // TODO(brettw) when we are not querying for the most recent visit only,
- // we should get all the visits in the time range for the given URL and add
- // separate results for each of them. Until then, just treat as unique:
- //
- // Just add this one visit for the last time they visited it, except for
- // starred only queries which have no visit times.
- if (options.only_starred) {
- url_result.set_visit_time(Time());
- } else {
- url_result.set_visit_time(url_result.last_visit());
- }
- our_results.AppendURLBySwapping(&url_result);
- }
-
- // Now prepend all of the bookmark matches we found. We do this by appending
- // the old values to the new ones and swapping the results.
- if (our_results.size() > 0) {
- our_results.AppendResultsBySwapping(results,
- options.most_recent_visit_only);
- our_results.Swap(results);
- }
-}
-
void HistoryBackend::QueryHistoryFTS(const std::wstring& text_query,
const QueryOptions& options,
QueryResults* result) {
@@ -1162,8 +1093,6 @@ void HistoryBackend::QueryHistoryFTS(const std::wstring& text_query,
if (!url_result.url().is_valid())
continue; // Don't report invalid URLs in case of corruption.
- if (options.only_starred && !url_result.star_id())
- continue; // Don't add this unstarred item.
// Copy over the FTS stuff that the URLDatabase doesn't know about.
// We do this with swap() to avoid copying, since we know we don't
@@ -1179,21 +1108,10 @@ void HistoryBackend::QueryHistoryFTS(const std::wstring& text_query,
// has the time, we can avoid an extra query of the visits table.
url_result.set_visit_time(fts_matches[i].time);
- if (options.only_starred) {
- // When querying for starred pages fetch the starred entry.
- DCHECK(url_result.star_id());
- db_->GetStarredEntry(url_result.star_id(), &url_result.starred_entry_);
- } else {
- url_result.ResetStarredEntry();
- }
-
// Add it to the vector, this will clear our |url_row| object as a
// result of the swap.
result->AppendURLBySwapping(&url_result);
}
-
- if (options.include_all_starred)
- QueryStarredEntriesByText(&querier, text_query, options, result);
}
// Frontend to GetMostRecentRedirectsFrom from the history thread.
@@ -1399,7 +1317,7 @@ void HistoryBackend::SetImportedFavicons(
Time now = Time::Now();
// Track all starred URLs that had their favicons set or updated.
- std::set<GURL> starred_favicons_changed;
+ std::set<GURL> favicons_changed;
for (size_t i = 0; i < favicon_usage.size(); i++) {
FavIconID favicon_id = thumbnail_db_->GetFavIconIDForFavIconURL(
@@ -1422,16 +1340,15 @@ void HistoryBackend::SetImportedFavicons(
url_row.set_favicon_id(favicon_id);
db_->UpdateURLRow(url_row.id(), url_row);
- if (url_row.starred())
- starred_favicons_changed.insert(*url);
+ favicons_changed.insert(*url);
}
}
- if (!starred_favicons_changed.empty()) {
+ if (!favicons_changed.empty()) {
// Send the notification about the changed favicons for starred URLs.
FavIconChangeDetails* changed_details = new FavIconChangeDetails;
- changed_details->urls.swap(starred_favicons_changed);
- BroadcastNotifications(NOTIFY_STARRED_FAVICON_CHANGED, changed_details);
+ changed_details->urls.swap(favicons_changed);
+ BroadcastNotifications(NOTIFY_FAVICON_CHANGED, changed_details);
}
}
@@ -1544,7 +1461,7 @@ void HistoryBackend::SetFavIconMapping(const GURL& page_url,
redirects = &dummy_list;
}
- std::set<GURL> starred_favicons_changed;
+ std::set<GURL> favicons_changed;
// Save page <-> favicon association.
for (HistoryService::RedirectList::const_iterator i(redirects->begin());
@@ -1569,147 +1486,15 @@ void HistoryBackend::SetFavIconMapping(const GURL& page_url,
thumbnail_db_->DeleteFavIcon(old_id);
}
- if (row.starred())
- starred_favicons_changed.insert(row.url());
- }
-
- if (!starred_favicons_changed.empty()) {
- // Send the notification about the changed favicons for starred URLs.
- FavIconChangeDetails* changed_details = new FavIconChangeDetails;
- changed_details->urls.swap(starred_favicons_changed);
- BroadcastNotifications(NOTIFY_STARRED_FAVICON_CHANGED, changed_details);
- }
-
- ScheduleCommit();
-}
-
-void HistoryBackend::GetAllStarredEntries(
- scoped_refptr<GetStarredEntriesRequest> request) {
- if (request->canceled())
- return;
- // Only query for the entries if the starred table is valid. If the starred
- // table isn't valid, we may get back garbage which could cause the UI grief.
- //
- // TODO(sky): bug 1207654: this is temporary, the UI should really query for
- // valid state than avoid GetAllStarredEntries if not valid.
- if (db_.get() && db_->is_starred_valid())
- db_->GetStarredEntries(0, &(request->value));
- request->ForwardResult(
- GetStarredEntriesRequest::TupleType(request->handle(),
- &(request->value)));
-}
-
-void HistoryBackend::UpdateStarredEntry(const StarredEntry& new_entry) {
- if (!db_.get())
- return;
-
- StarredEntry resulting_entry = new_entry;
- if (!db_->UpdateStarredEntry(&resulting_entry) || !delegate_.get())
- return;
-
- ScheduleCommit();
-
- // Send out notification that the star entry changed.
- StarredEntryDetails* entry_details = new StarredEntryDetails();
- entry_details->entry = resulting_entry;
- BroadcastNotifications(NOTIFY_STAR_ENTRY_CHANGED, entry_details);
-}
-
-void HistoryBackend::CreateStarredEntry(
- scoped_refptr<CreateStarredEntryRequest> request,
- const StarredEntry& entry) {
- // This method explicitly allows request to be NULL.
- if (request.get() && request->canceled())
- return;
-
- StarID id = 0;
- StarredEntry resulting_entry(entry);
- if (db_.get()) {
- if (entry.type == StarredEntry::USER_GROUP) {
- id = db_->CreateStarredEntry(&resulting_entry);
- if (id) {
- // Broadcast group created notifications.
- StarredEntryDetails* entry_details = new StarredEntryDetails;
- entry_details->entry = resulting_entry;
- BroadcastNotifications(NOTIFY_STAR_GROUP_CREATED, entry_details);
- }
- } else if (entry.type == StarredEntry::URL) {
- // Currently, we only allow one starred entry for this URL. Therefore, we
- // check for an existing starred entry for this URL and update it if it
- // exists.
- if (!db_->GetStarIDForEntry(resulting_entry)) {
- // Adding a new starred URL.
- id = db_->CreateStarredEntry(&resulting_entry);
-
- // Broadcast starred notification.
- URLsStarredDetails* details = new URLsStarredDetails(true);
- details->changed_urls.insert(resulting_entry.url);
- details->star_entries.push_back(resulting_entry);
- BroadcastNotifications(NOTIFY_URLS_STARRED, details);
- } else {
- // Updating an existing one.
- db_->UpdateStarredEntry(&resulting_entry);
-
- // Broadcast starred update notification.
- StarredEntryDetails* entry_details = new StarredEntryDetails;
- entry_details->entry = resulting_entry;
- BroadcastNotifications(NOTIFY_STAR_ENTRY_CHANGED, entry_details);
- }
- } else {
- NOTREACHED();
- }
- }
-
- ScheduleCommit();
-
- if (request.get()) {
- request->ForwardResult(
- CreateStarredEntryRequest::TupleType(request->handle(), id));
+ favicons_changed.insert(row.url());
}
-}
-void HistoryBackend::DeleteStarredGroup(UIStarID group_id) {
- if (!db_.get())
- return;
-
- DeleteStarredEntry(db_->GetStarIDForGroupID(group_id));
-}
-
-void HistoryBackend::DeleteStarredURL(const GURL& url) {
- if (!db_.get())
- return;
-
- history::StarredEntry entry;
- entry.url = url;
- DeleteStarredEntry(db_->GetStarIDForEntry(entry));
-}
-
-void HistoryBackend::DeleteStarredEntry(history::StarID star_id) {
- if (!star_id) {
- NOTREACHED() << "Deleting a nonexistent entry";
- return;
- }
-
- // Delete the entry.
- URLsStarredDetails* details = new URLsStarredDetails(false);
- db_->DeleteStarredEntry(star_id, &details->changed_urls,
- &details->star_entries);
+ // Send the notification about the changed favicons.
+ FavIconChangeDetails* changed_details = new FavIconChangeDetails;
+ changed_details->urls.swap(favicons_changed);
+ BroadcastNotifications(NOTIFY_FAVICON_CHANGED, changed_details);
ScheduleCommit();
-
- BroadcastNotifications(NOTIFY_URLS_STARRED, details);
-}
-
-void HistoryBackend::GetMostRecentStarredEntries(
- scoped_refptr<GetMostRecentStarredEntriesRequest> request,
- int max_count) {
- if (request->canceled())
- return;
- if (db_.get())
- db_->GetMostRecentStarredEntries(max_count, &(request->value));
- request->ForwardResult(
- GetMostRecentStarredEntriesRequest::TupleType(request->handle(),
- &(request->value)));
}
void HistoryBackend::Commit() {
@@ -1859,6 +1644,11 @@ void HistoryBackend::ProcessDBTask(
}
}
+void HistoryBackend::ProcessEmptyRequest(
+ scoped_refptr<EmptyHistoryRequest> request) {
+ request->ForwardResult(EmptyHistoryRequest::TupleType());
+}
+
void HistoryBackend::BroadcastNotifications(
NotificationType type,
HistoryDetails* details_deleted) {
@@ -1887,7 +1677,6 @@ void HistoryBackend::DeleteAllHistory() {
// Get starred entries and their corresponding URL rows.
std::vector<StarredEntry> starred_entries;
- db_->GetStarredEntries(0, &starred_entries);
std::vector<URLRow> kept_urls;
for (size_t i = 0; i < starred_entries.size(); i++) {
@@ -2032,19 +1821,6 @@ bool HistoryBackend::ClearAllMainHistory(
if (!db_->CommitTemporaryURLTable())
return false;
- // The starred table references the old URL IDs. We need to fix it up to refer
- // to the new ones.
- for (std::vector<StarredEntry>::iterator i = starred_entries->begin();
- i != starred_entries->end();
- ++i) {
- if (i->type != StarredEntry::URL)
- continue;
-
- DCHECK(old_to_new.find(i->url_id) != old_to_new.end());
- i->url_id = old_to_new[i->url_id];
- db_->UpdateURLIDForStar(i->id, i->url_id);
- }
-
// Delete the old tables and recreate them empty.
db_->RecreateAllButStarAndURLTables();
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index c1136de..f73e653 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -205,26 +205,6 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
void SetImportedFavicons(
const std::vector<ImportedFavIconUsage>& favicon_usage);
- // Starring ------------------------------------------------------------------
-
- void GetAllStarredEntries(
- scoped_refptr<GetStarredEntriesRequest> request);
-
- void UpdateStarredEntry(const StarredEntry& new_entry);
-
- void CreateStarredEntry(scoped_refptr<CreateStarredEntryRequest> request,
- const StarredEntry& entry);
-
- void DeleteStarredGroup(UIStarID group_id);
-
- void DeleteStarredURL(const GURL& url);
-
- void DeleteStarredEntry(history::StarID star_id);
-
- void GetMostRecentStarredEntries(
- scoped_refptr<GetMostRecentStarredEntriesRequest> request,
- int max_count);
-
// Downloads -----------------------------------------------------------------
void QueryDownloads(scoped_refptr<DownloadQueryRequest> request);
@@ -263,6 +243,8 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
void ProcessDBTask(scoped_refptr<HistoryDBTaskRequest> request);
+ void ProcessEmptyRequest(scoped_refptr<EmptyHistoryRequest> request);
+
// Deleting ------------------------------------------------------------------
void DeleteURL(const GURL& url);
@@ -338,15 +320,6 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
const QueryOptions& options,
QueryResults* result);
- // Queries the starred database for all URL entries whose title contains the
- // specified text. This is called as necessary from QueryHistoryFTS. The
- // matches will be added to the beginning of the result vector in no
- // particular order.
- void QueryStarredEntriesByText(URLQuerier* querier,
- const std::wstring& text_query,
- const QueryOptions& options,
- QueryResults* results);
-
// Committing ----------------------------------------------------------------
// We always keep a transaction open on the history database so that multiple
diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc
index e1e6ffe..68bfc19 100644
--- a/chrome/browser/history/history_backend_unittest.cc
+++ b/chrome/browser/history/history_backend_unittest.cc
@@ -205,14 +205,6 @@ TEST_F(HistoryBackendTest, DeleteAll) {
JPEGCodec::Decode(kWeewarThumbnail, sizeof(kWeewarThumbnail)));
backend_->thumbnail_db_->SetPageThumbnail(row2_id, *weewar_bitmap, score);
- // Mark one of the URLs bookmarked.
- StarredEntry entry;
- entry.type = StarredEntry::URL;
- entry.url = row1.url();
- entry.parent_group_id = HistoryService::kBookmarkBarID;
- StarID star_id = backend_->db_->CreateStarredEntry(&entry);
- ASSERT_TRUE(star_id);
-
// Set full text index for each one.
backend_->text_database_->AddPageData(row1.url(), row1_id, visit1_id,
row1.last_visit(),
@@ -224,12 +216,8 @@ TEST_F(HistoryBackendTest, DeleteAll) {
// Now finally clear all history.
backend_->DeleteAllHistory();
- // The first URL should be preserved, along with its visits, but the time
- // should be cleared.
- EXPECT_TRUE(backend_->db_->GetRowForURL(row1.url(), &outrow1));
- EXPECT_EQ(2, outrow1.visit_count());
- EXPECT_EQ(1, outrow1.typed_count());
- EXPECT_TRUE(Time() == outrow1.last_visit());
+ // The first URL should be deleted.
+ EXPECT_FALSE(backend_->db_->GetRowForURL(row1.url(), &outrow1));
// The second row should be deleted.
URLRow outrow2;
@@ -246,27 +234,15 @@ TEST_F(HistoryBackendTest, DeleteAll) {
&out_data));
EXPECT_FALSE(backend_->thumbnail_db_->GetPageThumbnail(row2_id, &out_data));
- // We should have a favicon for the first URL only. We look them up by favicon
- // URL since the IDs may hav changed.
+ // Make sure the favicons were deleted.
+ // TODO(sky): would be nice if this didn't happen.
FavIconID out_favicon1 = backend_->thumbnail_db_->
GetFavIconIDForFavIconURL(favicon_url1);
- EXPECT_TRUE(out_favicon1);
+ EXPECT_FALSE(out_favicon1);
FavIconID out_favicon2 = backend_->thumbnail_db_->
GetFavIconIDForFavIconURL(favicon_url2);
EXPECT_FALSE(out_favicon2) << "Favicon not deleted";
- // The remaining URL should still reference the same favicon, even if its
- // ID has changed.
- EXPECT_EQ(out_favicon1, outrow1.favicon_id());
-
- // The first URL should still be bookmarked and have an entry. The star ID
- // must not have changed.
- EXPECT_TRUE(outrow1.starred());
- StarredEntry outentry;
- EXPECT_TRUE(backend_->db_->GetStarredEntry(star_id, &outentry));
- EXPECT_EQ(outrow1.id(), outentry.url_id);
- EXPECT_TRUE(outrow1.url() == outentry.url);
-
// The full text database should have no data.
std::vector<TextDatabase::Match> text_matches;
Time first_time_searched;
diff --git a/chrome/browser/history/history_database.cc b/chrome/browser/history/history_database.cc
index e606aeb..d79d14a 100644
--- a/chrome/browser/history/history_database.cc
+++ b/chrome/browser/history/history_database.cc
@@ -43,7 +43,7 @@ namespace history {
namespace {
// Current version number.
-const int kCurrentVersionNumber = 15;
+const int kCurrentVersionNumber = 16;
} // namespace
@@ -55,7 +55,8 @@ HistoryDatabase::HistoryDatabase()
HistoryDatabase::~HistoryDatabase() {
}
-InitStatus HistoryDatabase::Init(const std::wstring& history_name) {
+InitStatus HistoryDatabase::Init(const std::wstring& history_name,
+ const std::wstring& bookmarks_path) {
// Open the history database, using the narrow version of open indicates to
// sqlite that we want the database to be in UTF-8 if it doesn't already
// exist.
@@ -94,18 +95,16 @@ InitStatus HistoryDatabase::Init(const std::wstring& history_name) {
return INIT_FAILURE;
if (!CreateURLTable(false) || !InitVisitTable() ||
!InitKeywordSearchTermsTable() || !InitDownloadTable() ||
- !InitSegmentTables() || !InitStarTable())
+ !InitSegmentTables())
return INIT_FAILURE;
CreateMainURLIndex();
CreateSupplimentaryURLIndices();
// Version check.
- InitStatus version_status = EnsureCurrentVersion();
+ InitStatus version_status = EnsureCurrentVersion(bookmarks_path);
if (version_status != INIT_OK)
return version_status;
- EnsureStarredIntegrity();
-
// Succeeded: keep the DB open by detaching the auto-closer.
scoper.Detach();
db_closer_.Attach(&db_, &statement_cache_);
@@ -222,7 +221,8 @@ SqliteStatementCache& HistoryDatabase::GetStatementCache() {
// Migration -------------------------------------------------------------------
-InitStatus HistoryDatabase::EnsureCurrentVersion() {
+InitStatus HistoryDatabase::EnsureCurrentVersion(
+ const std::wstring& tmp_bookmarks_path) {
// We can't read databases newer than we were designed for.
if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber)
return INIT_TOO_NEW;
@@ -239,6 +239,16 @@ InitStatus HistoryDatabase::EnsureCurrentVersion() {
// Put migration code here
+ if (cur_version == 15) {
+ if (!MigrateBookmarksToFile(tmp_bookmarks_path))
+ return INIT_FAILURE;
+ if (!DropStarredIDFromURLs())
+ return INIT_FAILURE;
+ cur_version = 16;
+ meta_table_.SetVersionNumber(cur_version);
+ meta_table_.SetCompatibleVersionNumber(cur_version);
+ }
+
LOG_IF(WARNING, cur_version < kCurrentVersionNumber) <<
"History database version " << cur_version << " is too old to handle.";
diff --git a/chrome/browser/history/history_database.h b/chrome/browser/history/history_database.h
index 92c356d..f386a2a 100644
--- a/chrome/browser/history/history_database.h
+++ b/chrome/browser/history/history_database.h
@@ -56,6 +56,9 @@ class TextDatabaseManager;
// as the storage interface. Logic for manipulating this storage layer should
// be in HistoryBackend.cc.
class HistoryDatabase : public DownloadDatabase,
+ // TODO(sky): See if we can nuke StarredURLDatabase and just create on the
+ // stack for migration. Then HistoryDatabase would directly descend from
+ // URLDatabase.
public StarredURLDatabase,
public VisitDatabase,
public VisitSegmentDatabase {
@@ -84,7 +87,8 @@ class HistoryDatabase : public DownloadDatabase,
// Must call this function to complete initialization. Will return true on
// success. On false, no other function should be called. You may want to call
// BeginExclusiveMode after this when you are ready.
- InitStatus Init(const std::wstring& history_name);
+ InitStatus Init(const std::wstring& history_name,
+ const std::wstring& tmp_bookmarks_path);
// Call to set the mode on the database to exclusive. The default locking mode
// is "normal" but we want to run in exclusive mode for slightly better
@@ -141,6 +145,9 @@ class HistoryDatabase : public DownloadDatabase,
// visit id wasn't found.
SegmentID GetSegmentID(VisitID visit_id);
+ // Drops the starred table and star_id from urls.
+ bool MigrateFromVersion15ToVersion16();
+
private:
// Implemented for URLDatabase.
virtual sqlite3* GetDB();
@@ -161,7 +168,7 @@ class HistoryDatabase : public DownloadDatabase,
//
// This assumes it is called from the init function inside a transaction. It
// may commit the transaction and start a new one if migration requires it.
- InitStatus EnsureCurrentVersion();
+ InitStatus EnsureCurrentVersion(const std::wstring& tmp_bookmarks_path);
// ---------------------------------------------------------------------------
diff --git a/chrome/browser/history/history_marshaling.h b/chrome/browser/history/history_marshaling.h
index d1c4501..d0722e4 100644
--- a/chrome/browser/history/history_marshaling.h
+++ b/chrome/browser/history/history_marshaling.h
@@ -102,19 +102,6 @@ typedef CancelableRequest<HistoryService::ThumbnailDataCallback>
typedef CancelableRequest<HistoryService::FavIconDataCallback>
GetFavIconRequest;
-// Starring -------------------------------------------------------------------
-
-typedef CancelableRequest1<HistoryService::GetStarredEntriesCallback,
- std::vector<history::StarredEntry> >
- GetStarredEntriesRequest;
-
-typedef CancelableRequest1<HistoryService::GetMostRecentStarredEntriesCallback,
- std::vector<history::StarredEntry> >
- GetMostRecentStarredEntriesRequest;
-
-typedef CancelableRequest<HistoryService::CreateStarredEntryCallback>
- CreateStarredEntryRequest;
-
// Downloads ------------------------------------------------------------------
typedef CancelableRequest1<HistoryService::DownloadQueryCallback,
@@ -155,6 +142,9 @@ typedef CancelableRequest1<HistoryService::HistoryDBTaskCallback,
scoped_refptr<HistoryDBTask> >
HistoryDBTaskRequest;
+typedef CancelableRequest<HistoryService::EmptyHistoryCallback>
+ EmptyHistoryRequest;
+
} // namespace history
#endif // CHROME_BROWSER_HISTORY_HISTORY_MARSHALING_H__
diff --git a/chrome/browser/history/history_notifications.h b/chrome/browser/history/history_notifications.h
index d5146ea..66379fd 100644
--- a/chrome/browser/history/history_notifications.h
+++ b/chrome/browser/history/history_notifications.h
@@ -72,7 +72,6 @@ struct URLsDeletedDetails : public HistoryDetails {
// Details for NOTIFY_URLS_STARRED.
struct URLsStarredDetails : public HistoryDetails {
-
URLsStarredDetails(bool being_starred) : starred(being_starred) {}
// The new starred state of the list of URLs. True when they are being
@@ -81,18 +80,9 @@ struct URLsStarredDetails : public HistoryDetails {
// The list of URLs that are changing.
std::set<GURL> changed_urls;
-
- // The star entries that were added or removed as the result of starring
- // the entry. This may be empty.
- std::vector<StarredEntry> star_entries;
-};
-
-// Details for NOTIFY_STAR_ENTRY_CHANGED and others.
-struct StarredEntryDetails : public HistoryDetails {
- StarredEntry entry;
};
-// Details for NOTIFY_STARRED_FAVICON_CHANGED.
+// Details for NOTIFY_FAVICON_CHANGED.
struct FavIconChangeDetails : public HistoryDetails {
std::set<GURL> urls;
};
diff --git a/chrome/browser/history/history_querying_unittest.cc b/chrome/browser/history/history_querying_unittest.cc
index 9d5f74d..7f4c7d5 100644
--- a/chrome/browser/history/history_querying_unittest.cc
+++ b/chrome/browser/history/history_querying_unittest.cc
@@ -132,19 +132,6 @@ class HistoryQueryTest : public testing::Test {
history_->SetPageTitle(url, test_entries[i].title);
history_->SetPageContents(url, test_entries[i].body);
}
-
- // Set one of the pages starred.
- history::StarredEntry entry;
- entry.id = 5;
- entry.title = L"Some starred page";
- entry.date_added = Time::Now();
- entry.parent_group_id = StarredEntry::BOOKMARK_BAR;
- entry.group_id = 0;
- entry.visual_order = 0;
- entry.type = history::StarredEntry::URL;
- entry.url = GURL(test_entries[0].url);
- entry.date_group_modified = Time::Now();
- history_->CreateStarredEntry(entry, NULL, NULL);
}
virtual void TearDown() {
@@ -189,9 +176,6 @@ TEST_F(HistoryQueryTest, Basic) {
EXPECT_TRUE(NthResultIs(results, 3, 1));
EXPECT_TRUE(NthResultIs(results, 4, 0));
- // Check that the starred one is marked starred.
- EXPECT_TRUE(results[4].starred());
-
// Next query a time range. The beginning should be inclusive, the ending
// should be exclusive.
options.begin_time = test_entries[3].time;
@@ -247,11 +231,10 @@ TEST_F(HistoryQueryTest, FTS) {
// this query will return the starred item twice since we requested all
// starred entries and no de-duping.
QueryHistory(std::wstring(L"some"), options, &results);
- EXPECT_EQ(4, results.size());
- EXPECT_TRUE(NthResultIs(results, 0, 4)); // Starred item.
- EXPECT_TRUE(NthResultIs(results, 1, 2));
- EXPECT_TRUE(NthResultIs(results, 2, 3));
- EXPECT_TRUE(NthResultIs(results, 3, 1));
+ EXPECT_EQ(3, results.size());
+ EXPECT_TRUE(NthResultIs(results, 0, 2));
+ EXPECT_TRUE(NthResultIs(results, 1, 3));
+ EXPECT_TRUE(NthResultIs(results, 2, 1));
// Do a query that should only match one of them.
QueryHistory(std::wstring(L"PAGETWO"), options, &results);
@@ -262,7 +245,6 @@ TEST_F(HistoryQueryTest, FTS) {
// should be exclusive.
options.begin_time = test_entries[1].time;
options.end_time = test_entries[3].time;
- options.include_all_starred = false;
QueryHistory(std::wstring(L"some"), options, &results);
EXPECT_EQ(1, results.size());
EXPECT_TRUE(NthResultIs(results, 0, 1));
@@ -295,10 +277,9 @@ TEST_F(HistoryQueryTest, FTSCount) {
// get the N most recent entries.
options.max_count = 2;
QueryHistory(std::wstring(L"some"), options, &results);
- EXPECT_EQ(3, results.size());
- EXPECT_TRUE(NthResultIs(results, 0, 4));
- EXPECT_TRUE(NthResultIs(results, 1, 2));
- EXPECT_TRUE(NthResultIs(results, 2, 3));
+ EXPECT_EQ(2, results.size());
+ EXPECT_TRUE(NthResultIs(results, 0, 2));
+ EXPECT_TRUE(NthResultIs(results, 1, 3));
// Now query a subset of the pages and limit by N items. "FOO" should match
// the 2nd & 3rd pages, but we should only get the 3rd one because of the one
diff --git a/chrome/browser/history/history_types.cc b/chrome/browser/history/history_types.cc
index 920b0bc..758a166 100644
--- a/chrome/browser/history/history_types.cc
+++ b/chrome/browser/history/history_types.cc
@@ -43,7 +43,6 @@ void URLRow::Swap(URLRow* other) {
std::swap(typed_count_, other->typed_count_);
std::swap(last_visit_, other->last_visit_);
std::swap(hidden_, other->hidden_);
- std::swap(star_id_, other->star_id_);
std::swap(favicon_id_, other->favicon_id_);
}
@@ -54,7 +53,6 @@ void URLRow::Initialize() {
last_visit_ = Time();
hidden_ = false;
favicon_id_ = 0;
- star_id_ = 0;
}
// VisitRow --------------------------------------------------------------------
@@ -113,7 +111,6 @@ void URLResult::Swap(URLResult* other) {
std::swap(visit_time_, other->visit_time_);
snippet_.Swap(&other->snippet_);
title_match_positions_.swap(other->title_match_positions_);
- starred_entry_.Swap(&other->starred_entry_);
}
// QueryResults ----------------------------------------------------------------
diff --git a/chrome/browser/history/history_types.h b/chrome/browser/history/history_types.h
index 738eda02..cbbd1f7 100644
--- a/chrome/browser/history/history_types.h
+++ b/chrome/browser/history/history_types.h
@@ -136,14 +136,6 @@ class URLRow {
hidden_ = hidden;
}
- StarID star_id() const { return star_id_; }
- void set_star_id(StarID star_id) {
- star_id_ = star_id;
- }
-
- // Simple boolean query to see if the page is starred.
- bool starred() const { return (star_id_ != 0); }
-
// ID of the favicon. A value of 0 means the favicon isn't known yet.
FavIconID favicon_id() const { return favicon_id_; }
void set_favicon_id(FavIconID favicon_id) {
@@ -190,13 +182,6 @@ class URLRow {
// is usually for subframes.
bool hidden_;
- // ID of the starred entry.
- //
- // NOTE: This is ignored by Add/UpdateURL. To modify the starred state you
- // must invoke SetURLStarred.
- // TODO: revisit this to see if this limitation can be removed.
- StarID star_id_;
-
// The ID of the favicon for this url.
FavIconID favicon_id_;
@@ -372,11 +357,6 @@ class URLResult : public URLRow {
virtual void Swap(URLResult* other);
- // Returns the starred entry for this url. This is only set if the query
- // was configured to search for starred only entries (only_starred is true).
- const StarredEntry& starred_entry() const { return starred_entry_; }
- void ResetStarredEntry() { starred_entry_ = StarredEntry(); }
-
private:
friend class HistoryBackend;
@@ -387,9 +367,6 @@ class URLResult : public URLRow {
Snippet snippet_;
Snippet::MatchPositions title_match_positions_;
- // See comment above getter.
- StarredEntry starred_entry_;
-
// We support the implicit copy constructor and operator=.
};
@@ -488,8 +465,6 @@ class QueryResults {
struct QueryOptions {
QueryOptions()
: most_recent_visit_only(false),
- only_starred(false),
- include_all_starred(true),
max_count(0) {
}
@@ -521,26 +496,6 @@ struct QueryOptions {
// Defaults to false (all visits).
bool most_recent_visit_only;
- // Indicates if only starred items should be matched.
- //
- // Defaults to false.
- bool only_starred;
-
- // When true, and we're doing a full text query, starred entries that have
- // never been visited or have been visited outside of the given time range
- // will also be included in the results. These items will appear at the
- // beginning of the result set. Non-full-text queries won't check this flag
- // and will never return unvisited bookmarks.
- //
- // When false, full text queries will not return unvisited bookmarks, they
- // will only be included when they were visited in the given time range.
- //
- // You probably want to use this in conjunction with most_recent_visit_only
- // since it will cause duplicates otherwise.
- //
- // Defaults to true.
- bool include_all_starred;
-
// The maximum number of results to return. The results will be sorted with
// the most recent first, so older results may not be returned if there is not
// enough room. When 0, this will return everything (the default).
diff --git a/chrome/browser/history/history_unittest.cc b/chrome/browser/history/history_unittest.cc
index 37b9179..cc0bfb4 100644
--- a/chrome/browser/history/history_unittest.cc
+++ b/chrome/browser/history/history_unittest.cc
@@ -120,12 +120,6 @@ class BackendDelegate : public HistoryBackend::Delegate {
HistoryTest* history_test_;
};
-bool IsURLStarred(URLDatabase* db, const GURL& url) {
- URLRow row;
- EXPECT_TRUE(db->GetRowForURL(url, &row)) << "URL not found";
- return row.starred();
-}
-
} // namespace
// This must be outside the anonymous namespace for the friend statement in
@@ -272,21 +266,6 @@ class HistoryTest : public testing::Test {
MessageLoop::current()->Quit();
}
- void SetURLStarred(const GURL& url, bool starred) {
- history::StarredEntry entry;
- entry.type = history::StarredEntry::URL;
- entry.url = url;
- history::StarID star_id = db_->GetStarIDForEntry(entry);
- if (star_id && !starred) {
- // Unstar.
- backend_->DeleteStarredEntry(star_id);
- } else if (!star_id && starred) {
- // Star.
- entry.parent_group_id = HistoryService::kBookmarkBarID;
- backend_->CreateStarredEntry(NULL, entry);
- }
- }
-
// PageUsageData vector to test segments.
ScopedVector<PageUsageData> page_usage_data_;
@@ -870,56 +849,4 @@ TEST_F(HistoryTest, HistoryDBTaskCanceled) {
ASSERT_FALSE(task->done_invoked);
}
-TEST_F(HistoryTest, Starring) {
- CreateBackendAndDatabase();
-
- // Add one page and star it.
- GURL simple_page("http://google.com");
- scoped_refptr<HistoryAddPageArgs> args(MakeAddArgs(simple_page));
- backend_->AddPage(args);
- EXPECT_FALSE(IsURLStarred(db_, simple_page));
- EXPECT_FALSE(IsURLStarred(in_mem_backend_->db(), simple_page));
- SetURLStarred(simple_page, true);
-
- // The URL should be starred in both the main and memory DBs.
- EXPECT_TRUE(IsURLStarred(db_, simple_page));
- EXPECT_TRUE(IsURLStarred(in_mem_backend_->db(), simple_page));
-
- // Unstar it.
- SetURLStarred(simple_page, false);
- EXPECT_FALSE(IsURLStarred(db_, simple_page));
- EXPECT_FALSE(IsURLStarred(in_mem_backend_->db(), simple_page));
-}
-
-TEST_F(HistoryTest, SetStarredOnPageWithTypeCount0) {
- CreateBackendAndDatabase();
-
- // Add a page to the backend.
- const GURL url(L"http://google.com/");
- scoped_refptr<HistoryAddPageArgs> args(new HistoryAddPageArgs(
- url, Time::Now(), NULL, 1, GURL(), HistoryService::RedirectList(),
- PageTransition::LINK));
- backend_->AddPage(args);
-
- // Now fetch the URLInfo from the in memory db, it should not be there since
- // it was not typed.
- URLRow url_info;
- EXPECT_EQ(0, in_mem_backend_->db()->GetRowForURL(url, &url_info));
-
- // Mark the URL starred.
- SetURLStarred(url, true);
-
- // The type count is 0, so the page shouldn't be starred in the in memory
- // db.
- EXPECT_EQ(0, in_mem_backend_->db()->GetRowForURL(url, &url_info));
- EXPECT_TRUE(IsURLStarred(db_, url));
-
- // Now unstar it.
- SetURLStarred(url, false);
-
- // Make sure both the back end and in memory DB think it is unstarred.
- EXPECT_EQ(0, in_mem_backend_->db()->GetRowForURL(url, &url_info));
- EXPECT_FALSE(IsURLStarred(db_, url));
-}
-
} // namespace history
diff --git a/chrome/browser/history/in_memory_history_backend.cc b/chrome/browser/history/in_memory_history_backend.cc
index b3619a9..d745423 100644
--- a/chrome/browser/history/in_memory_history_backend.cc
+++ b/chrome/browser/history/in_memory_history_backend.cc
@@ -54,7 +54,6 @@ InMemoryHistoryBackend::~InMemoryHistoryBackend() {
service->RemoveObserver(this, NOTIFY_HISTORY_URL_VISITED, source);
service->RemoveObserver(this, NOTIFY_HISTORY_TYPED_URLS_MODIFIED, source);
service->RemoveObserver(this, NOTIFY_HISTORY_URLS_DELETED, source);
- service->RemoveObserver(this, NOTIFY_URLS_STARRED, source);
}
}
@@ -87,7 +86,6 @@ void InMemoryHistoryBackend::AttachToHistoryService(Profile* profile) {
service->AddObserver(this, NOTIFY_HISTORY_URL_VISITED, source);
service->AddObserver(this, NOTIFY_HISTORY_TYPED_URLS_MODIFIED, source);
service->AddObserver(this, NOTIFY_HISTORY_URLS_DELETED, source);
- service->AddObserver(this, NOTIFY_URLS_STARRED, source);
}
void InMemoryHistoryBackend::Observe(NotificationType type,
@@ -110,9 +108,6 @@ void InMemoryHistoryBackend::Observe(NotificationType type,
case NOTIFY_HISTORY_URLS_DELETED:
OnURLsDeleted(*Details<history::URLsDeletedDetails>(details).ptr());
break;
- case NOTIFY_URLS_STARRED:
- OnURLsStarred(*Details<history::URLsStarredDetails>(details).ptr());
- break;
default:
// For simplicity, the unit tests send us all notifications, even when
// we haven't registered for them, so don't assert here.
@@ -164,21 +159,4 @@ void InMemoryHistoryBackend::OnURLsDeleted(const URLsDeletedDetails& details) {
}
}
-void InMemoryHistoryBackend::OnURLsStarred(
- const history::URLsStarredDetails& details) {
- DCHECK(db_.get());
-
- for (std::set<GURL>::const_iterator i = details.changed_urls.begin();
- i != details.changed_urls.end(); ++i) {
- URLRow row;
- if (db_->GetRowForURL(*i, &row)) {
- // NOTE: We currently don't care about the star id from the in memory
- // db, so that we use a fake value. If this does become a problem,
- // then the notification will have to propagate the star id.
- row.set_star_id(details.starred ? kBogusStarredID : 0);
- db_->UpdateURLRow(row.id(), row);
- }
- }
-}
-
} // namespace history
diff --git a/chrome/browser/history/in_memory_history_backend.h b/chrome/browser/history/in_memory_history_backend.h
index 9134bf0..c86ea56 100644
--- a/chrome/browser/history/in_memory_history_backend.h
+++ b/chrome/browser/history/in_memory_history_backend.h
@@ -85,9 +85,6 @@ class InMemoryHistoryBackend : public NotificationObserver {
// Handler for NOTIFY_HISTORY_URLS_DELETED.
void OnURLsDeleted(const URLsDeletedDetails& details);
- // Handler for NOTIFY_URLS_STARRED.
- void OnURLsStarred(const URLsStarredDetails& details);
-
scoped_ptr<InMemoryDatabase> db_;
// The profile that this object is attached. May be NULL before
diff --git a/chrome/browser/history/starred_url_database.cc b/chrome/browser/history/starred_url_database.cc
index 7294222..950cee3 100644
--- a/chrome/browser/history/starred_url_database.cc
+++ b/chrome/browser/history/starred_url_database.cc
@@ -29,7 +29,11 @@
#include "chrome/browser/history/starred_url_database.h"
+#include "base/file_util.h"
#include "base/logging.h"
+#include "base/json_writer.h"
+#include "chrome/browser/bookmark_bar_model.h"
+#include "chrome/browser/bookmark_codec.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/query_parser.h"
#include "chrome/browser/meta_table_helper.h"
@@ -102,181 +106,35 @@ void FillInStarredEntry(SQLStatement* s, StarredEntry* entry) {
} // namespace
-StarredURLDatabase::StarredURLDatabase()
- : is_starred_valid_(true), check_starred_integrity_on_mutation_(true) {
+StarredURLDatabase::StarredURLDatabase() {
}
StarredURLDatabase::~StarredURLDatabase() {
}
-bool StarredURLDatabase::InitStarTable() {
- if (!DoesSqliteTableExist(GetDB(), "starred")) {
- if (sqlite3_exec(GetDB(), "CREATE TABLE starred ("
- "id INTEGER PRIMARY KEY,"
- "type INTEGER NOT NULL DEFAULT 0,"
- "url_id INTEGER NOT NULL DEFAULT 0,"
- "group_id INTEGER NOT NULL DEFAULT 0,"
- "title VARCHAR,"
- "date_added INTEGER NOT NULL,"
- "visual_order INTEGER DEFAULT 0,"
- "parent_id INTEGER DEFAULT 0,"
- "date_modified INTEGER DEFAULT 0 NOT NULL)",
- NULL, NULL, NULL) != SQLITE_OK) {
- NOTREACHED();
- return false;
- }
- if (sqlite3_exec(GetDB(), "CREATE INDEX starred_index "
- "ON starred(id,url_id)", NULL, NULL, NULL)) {
- NOTREACHED();
- return false;
- }
- // Add an entry that represents the bookmark bar. The title is ignored in
- // the UI.
- StarID bookmark_id = CreateStarredEntryRow(
- 0, HistoryService::kBookmarkBarID, 0, L"bookmark-bar", Time::Now(), 0,
- history::StarredEntry::BOOKMARK_BAR);
- if (bookmark_id != HistoryService::kBookmarkBarID) {
- NOTREACHED();
- return false;
- }
-
- // Add an entry that represents other. The title is ignored in the UI.
- StarID other_id = CreateStarredEntryRow(
- 0, HistoryService::kBookmarkBarID + 1, 0, L"other", Time::Now(), 0,
- history::StarredEntry::OTHER);
- if (!other_id) {
- NOTREACHED();
- return false;
- }
- }
-
- sqlite3_exec(GetDB(), "CREATE INDEX starred_group_index"
- "ON starred(group_id)", NULL, NULL, NULL);
- return true;
-}
-
-bool StarredURLDatabase::EnsureStarredIntegrity() {
- if (!is_starred_valid_)
- return false;
-
- // Assume invalid, we'll set to true if succesful.
- is_starred_valid_ = false;
-
- std::set<StarredNode*> roots;
- std::set<StarID> groups_with_duplicate_ids;
- std::set<StarredNode*> unparented_urls;
- std::set<StarID> empty_url_ids;
-
- if (!BuildStarNodes(&roots, &groups_with_duplicate_ids, &unparented_urls,
- &empty_url_ids)) {
- return false;
- }
-
- // The table may temporarily get into an invalid state while updating the
- // integrity.
- bool org_check_starred_integrity_on_mutation =
- check_starred_integrity_on_mutation_;
- check_starred_integrity_on_mutation_ = false;
- is_starred_valid_ =
- EnsureStarredIntegrityImpl(&roots, groups_with_duplicate_ids,
- &unparented_urls, empty_url_ids);
- check_starred_integrity_on_mutation_ =
- org_check_starred_integrity_on_mutation;
-
- STLDeleteElements(&roots);
- STLDeleteElements(&unparented_urls);
- return is_starred_valid_;
-}
-
-StarID StarredURLDatabase::GetStarIDForEntry(const StarredEntry& entry) {
- if (entry.type == StarredEntry::URL) {
- URLRow url_row;
- URLID url_id = GetRowForURL(entry.url, &url_row);
- if (!url_id)
- return 0;
- return url_row.star_id();
- }
- return GetStarIDForGroupID(entry.group_id);
-}
-
-StarID StarredURLDatabase::GetStarIDForGroupID(UIStarID group_id) {
- DCHECK(group_id);
-
- SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
- "SELECT id FROM starred WHERE group_id = ?");
- if (!statement.is_valid())
- return false;
-
- statement->bind_int64(0, group_id);
- if (statement->step() == SQLITE_ROW)
- return statement->column_int64(0);
- return 0;
-}
-
-void StarredURLDatabase::DeleteStarredEntry(
- StarID star_id,
- std::set<GURL>* unstarred_urls,
- std::vector<StarredEntry>* deleted_entries) {
- DeleteStarredEntryImpl(star_id, unstarred_urls, deleted_entries);
- if (check_starred_integrity_on_mutation_)
- CheckStarredIntegrity();
-}
+bool StarredURLDatabase::MigrateBookmarksToFile(const std::wstring& path) {
+ if (!DoesSqliteTableExist(GetDB(), "starred"))
+ return true;
-bool StarredURLDatabase::UpdateStarredEntry(StarredEntry* entry) {
- // Determine the ID used by the database.
- const StarID id = GetStarIDForEntry(*entry);
- if (!id) {
- NOTREACHED() << "request to update unknown star entry";
+ if (EnsureStarredIntegrity() && !MigrateBookmarksToFileImpl(path)) {
+ NOTREACHED() << " Bookmarks migration failed";
return false;
}
- StarredEntry original_entry;
- if (!GetStarredEntry(id, &original_entry)) {
- NOTREACHED() << "Unknown star entry";
+ if (sqlite3_exec(GetDB(), "DROP TABLE starred", NULL, NULL,
+ NULL) != SQLITE_OK) {
+ NOTREACHED() << "Unable to drop starred table";
return false;
}
-
- if (entry->parent_group_id != original_entry.parent_group_id) {
- // Parent has changed.
- if (original_entry.parent_group_id) {
- AdjustStarredVisualOrder(original_entry.parent_group_id,
- original_entry.visual_order, -1);
- }
- if (entry->parent_group_id) {
- AdjustStarredVisualOrder(entry->parent_group_id, entry->visual_order, 1);
- }
- } else if (entry->visual_order != original_entry.visual_order &&
- entry->parent_group_id) {
- // Same parent, but visual order changed.
- // Shift everything down from the old location.
- AdjustStarredVisualOrder(original_entry.parent_group_id,
- original_entry.visual_order, -1);
- // Make room for new location by shifting everything up from the new
- // location.
- AdjustStarredVisualOrder(original_entry.parent_group_id,
- entry->visual_order, 1);
- }
-
- // And update title, parent and visual order.
- UpdateStarredEntryRow(id, entry->title, entry->parent_group_id,
- entry->visual_order, entry->date_group_modified);
- entry->url_id = original_entry.url_id;
- entry->date_added = original_entry.date_added;
- entry->id = original_entry.id;
- if (check_starred_integrity_on_mutation_)
- CheckStarredIntegrity();
return true;
}
-bool StarredURLDatabase::GetStarredEntries(
- UIStarID parent_group_id,
+bool StarredURLDatabase::GetAllStarredEntries(
std::vector<StarredEntry>* entries) {
DCHECK(entries);
std::string sql = "SELECT ";
sql.append(kHistoryStarFields);
sql.append("FROM starred LEFT JOIN urls ON starred.url_id = urls.id ");
- if (parent_group_id)
- sql += "WHERE starred.parent_id = ? ";
sql += "ORDER BY parent_id, visual_order";
SQLStatement s;
@@ -284,8 +142,6 @@ bool StarredURLDatabase::GetStarredEntries(
NOTREACHED() << "Statement prepare failed";
return false;
}
- if (parent_group_id)
- s.bind_int64(0, parent_group_id);
history::StarredEntry entry;
while (s.step() == SQLITE_ROW) {
@@ -299,6 +155,25 @@ bool StarredURLDatabase::GetStarredEntries(
return true;
}
+bool StarredURLDatabase::EnsureStarredIntegrity() {
+ std::set<StarredNode*> roots;
+ std::set<StarID> groups_with_duplicate_ids;
+ std::set<StarredNode*> unparented_urls;
+ std::set<StarID> empty_url_ids;
+
+ if (!BuildStarNodes(&roots, &groups_with_duplicate_ids, &unparented_urls,
+ &empty_url_ids)) {
+ return false;
+ }
+
+ bool valid = EnsureStarredIntegrityImpl(&roots, groups_with_duplicate_ids,
+ &unparented_urls, empty_url_ids);
+
+ STLDeleteElements(&roots);
+ STLDeleteElements(&unparented_urls);
+ return valid;
+}
+
bool StarredURLDatabase::UpdateStarredEntryRow(StarID star_id,
const std::wstring& title,
UIStarID parent_group_id,
@@ -380,8 +255,6 @@ StarID StarredURLDatabase::CreateStarredEntryRow(URLID url_id,
}
bool StarredURLDatabase::DeleteStarredEntryRow(StarID star_id) {
- if (check_starred_integrity_on_mutation_)
- DCHECK(star_id && star_id != HistoryService::kBookmarkBarID);
SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
"DELETE FROM starred WHERE id=?");
if (!statement.is_valid())
@@ -433,11 +306,6 @@ StarID StarredURLDatabase::CreateStarredEntry(StarredEntry* entry) {
url_row.set_hidden(false);
entry->url_id = this->AddURL(url_row);
} else {
- // Update the existing row for this URL.
- if (url_row.starred()) {
- DCHECK(false) << "We are starring an already-starred URL";
- return 0;
- }
entry->url_id = url_row.id(); // The caller doesn't have to set this.
}
@@ -447,7 +315,6 @@ StarID StarredURLDatabase::CreateStarredEntry(StarredEntry* entry) {
entry->visual_order, entry->type);
// Update the URL row to refer to this new starred entry.
- url_row.set_star_id(entry->id);
UpdateURLRow(entry->url_id, url_row);
break;
}
@@ -456,119 +323,9 @@ StarID StarredURLDatabase::CreateStarredEntry(StarredEntry* entry) {
NOTREACHED();
break;
}
- if (check_starred_integrity_on_mutation_)
- CheckStarredIntegrity();
return entry->id;
}
-void StarredURLDatabase::GetMostRecentStarredEntries(
- int max_count,
- std::vector<StarredEntry>* entries) {
- DCHECK(max_count && entries);
- SQLITE_UNIQUE_STATEMENT(s, GetStatementCache(),
- "SELECT" STAR_FIELDS "FROM starred "
- "LEFT JOIN urls ON starred.url_id = urls.id "
- "WHERE starred.type=0 ORDER BY starred.date_added DESC, "
- "starred.id DESC " // This is for testing, when the dates are
- // typically the same.
- "LIMIT ?");
- if (!s.is_valid())
- return;
- s->bind_int(0, max_count);
-
- while (s->step() == SQLITE_ROW) {
- history::StarredEntry entry;
- FillInStarredEntry(s.statement(), &entry);
- entries->push_back(entry);
- }
-}
-
-void StarredURLDatabase::GetURLsForTitlesMatching(const std::wstring& query,
- std::set<URLID>* ids) {
- QueryParser parser;
- ScopedVector<QueryNode> nodes;
- parser.ParseQuery(query, &nodes.get());
- if (nodes.empty())
- return;
-
- SQLITE_UNIQUE_STATEMENT(s, GetStatementCache(),
- "SELECT url_id, title FROM starred WHERE type=?");
- if (!s.is_valid())
- return;
-
- s->bind_int(0, static_cast<int>(StarredEntry::URL));
- while (s->step() == SQLITE_ROW) {
- if (parser.DoesQueryMatch(s->column_string16(1), nodes.get()))
- ids->insert(s->column_int64(0));
- }
-}
-
-bool StarredURLDatabase::UpdateURLIDForStar(StarID star_id, URLID new_url_id) {
- SQLITE_UNIQUE_STATEMENT(s, GetStatementCache(),
- "UPDATE starred SET url_id=? WHERE id=?");
- if (!s.is_valid())
- return false;
- s->bind_int64(0, new_url_id);
- s->bind_int64(1, star_id);
- return s->step() == SQLITE_DONE;
-}
-
-void StarredURLDatabase::DeleteStarredEntryImpl(
- StarID star_id,
- std::set<GURL>* unstarred_urls,
- std::vector<StarredEntry>* deleted_entries) {
-
- StarredEntry deleted_entry;
- if (!GetStarredEntry(star_id, &deleted_entry))
- return; // Couldn't find information on the entry.
-
- if (deleted_entry.type == StarredEntry::BOOKMARK_BAR ||
- deleted_entry.type == StarredEntry::OTHER) {
- return;
- }
-
- if (deleted_entry.parent_group_id != 0) {
- // This entry has a parent. All siblings after this entry need to be shifted
- // down by 1.
- AdjustStarredVisualOrder(deleted_entry.parent_group_id,
- deleted_entry.visual_order, -1);
- }
-
- deleted_entries->push_back(deleted_entry);
-
- switch (deleted_entry.type) {
- case StarredEntry::URL: {
- unstarred_urls->insert(deleted_entry.url);
-
- // Need to unmark the starred flag in the URL database.
- URLRow url_row;
- if (GetURLRow(deleted_entry.url_id, &url_row)) {
- url_row.set_star_id(0);
- UpdateURLRow(deleted_entry.url_id, url_row);
- }
- break;
- }
-
- case StarredEntry::USER_GROUP: {
- // Need to delete all the children of the group. Use the db version which
- // avoids shifting the visual order.
- std::vector<StarredEntry> descendants;
- GetStarredEntries(deleted_entry.group_id, &descendants);
- for (std::vector<StarredEntry>::iterator i =
- descendants.begin(); i != descendants.end(); ++i) {
- // Recurse down into the child.
- DeleteStarredEntryImpl(i->id, unstarred_urls, deleted_entries);
- }
- break;
- }
-
- default:
- NOTREACHED();
- break;
- }
- DeleteStarredEntryRow(star_id);
-}
-
UIStarID StarredURLDatabase::GetMaxGroupID() {
SQLStatement max_group_id_statement;
if (max_group_id_statement.prepare(GetDB(),
@@ -589,7 +346,7 @@ bool StarredURLDatabase::BuildStarNodes(
std::set<StarredNode*>* unparented_urls,
std::set<StarID>* empty_url_ids) {
std::vector<StarredEntry> star_entries;
- if (!GetStarredEntries(0, &star_entries)) {
+ if (!GetAllStarredEntries(&star_entries)) {
NOTREACHED() << "Unable to get bookmarks from database";
return false;
}
@@ -699,11 +456,9 @@ bool StarredURLDatabase::EnsureStarredIntegrityImpl(
if (!bookmark_node) {
LOG(WARNING) << "No bookmark bar folder in database";
// If there is no bookmark bar entry in the db things are really
- // screwed. The UI assumes the bookmark bar entry has a particular
- // ID which is hard to enforce when creating a new entry. As this
- // shouldn't happen, we take the drastic route of recreating the
- // entire table.
- return RecreateStarredEntries();
+ // screwed. Return false, which won't trigger migration and we'll just
+ // drop the tables.
+ return false;
}
// Make sure the other node exists.
@@ -803,86 +558,96 @@ bool StarredURLDatabase::Move(StarredNode* source, StarredNode* new_parent) {
return true;
}
-bool StarredURLDatabase::RecreateStarredEntries() {
- if (sqlite3_exec(GetDB(), "DROP TABLE starred", NULL, NULL,
- NULL) != SQLITE_OK) {
- NOTREACHED() << "Unable to drop starred table";
+bool StarredURLDatabase::MigrateBookmarksToFileImpl(const std::wstring& path) {
+ std::vector<history::StarredEntry> entries;
+ if (!GetAllStarredEntries(&entries))
return false;
- }
- if (!InitStarTable()) {
- NOTREACHED() << "Unable to create starred table";
- return false;
- }
-
- if (sqlite3_exec(GetDB(), "UPDATE urls SET starred_id=0", NULL, NULL,
- NULL) != SQLITE_OK) {
- NOTREACHED() << "Unable to mark all URLs as unstarred";
- return false;
+ // Create the bookmark bar and other folder nodes.
+ history::StarredEntry entry;
+ entry.type = history::StarredEntry::BOOKMARK_BAR;
+ BookmarkBarNode bookmark_bar_node(NULL, GURL());
+ bookmark_bar_node.Reset(entry);
+ entry.type = history::StarredEntry::OTHER;
+ BookmarkBarNode other_node(NULL, GURL());
+ other_node.Reset(entry);
+
+ std::map<history::UIStarID, history::StarID> group_id_to_id_map;
+ typedef std::map<history::StarID, BookmarkBarNode*> IDToNodeMap;
+ IDToNodeMap id_to_node_map;
+
+ history::UIStarID other_folder_group_id = 0;
+ history::StarID other_folder_id = 0;
+
+ // Iterate through the entries building a mapping between group_id and id.
+ for (std::vector<history::StarredEntry>::const_iterator i = entries.begin();
+ i != entries.end(); ++i) {
+ if (i->type != history::StarredEntry::URL) {
+ group_id_to_id_map[i->group_id] = i->id;
+ if (i->type == history::StarredEntry::OTHER) {
+ other_folder_id = i->id;
+ other_folder_group_id = i->group_id;
+ }
+ }
}
- return true;
-}
-void StarredURLDatabase::CheckVisualOrder(StarredNode* node) {
- for (int i = 0; i < node->GetChildCount(); ++i) {
- DCHECK(i == node->GetChild(i)->value.visual_order);
- CheckVisualOrder(node->GetChild(i));
- }
-}
+ // Register the bookmark bar and other folder nodes in the maps.
+ id_to_node_map[HistoryService::kBookmarkBarID] = &bookmark_bar_node;
+ group_id_to_id_map[HistoryService::kBookmarkBarID] =
+ HistoryService::kBookmarkBarID;
+ if (other_folder_group_id) {
+ id_to_node_map[other_folder_id] = &other_node;
+ group_id_to_id_map[other_folder_group_id] = other_folder_id;
+ }
+
+ // Iterate through the entries again creating the nodes.
+ for (std::vector<history::StarredEntry>::iterator i = entries.begin();
+ i != entries.end(); ++i) {
+ if (!i->parent_group_id) {
+ DCHECK(i->type == history::StarredEntry::BOOKMARK_BAR ||
+ i->type == history::StarredEntry::OTHER);
+ // Only entries with no parent should be the bookmark bar and other
+ // bookmarks folders.
+ continue;
+ }
-void StarredURLDatabase::CheckStarredIntegrity() {
-#ifndef NDEBUG
- std::set<StarredNode*> roots;
- std::set<StarID> groups_with_duplicate_ids;
- std::set<StarredNode*> unparented_urls;
- std::set<StarID> empty_url_ids;
+ BookmarkBarNode* node = id_to_node_map[i->id];
+ if (!node) {
+ // Creating a node results in creating the parent. As such, it is
+ // possible for the node representing a group to have been created before
+ // encountering the details.
- if (!BuildStarNodes(&roots, &groups_with_duplicate_ids, &unparented_urls,
- &empty_url_ids)) {
- return;
- }
+ // The created nodes are owned by the root node.
+ node = new BookmarkBarNode(NULL, i->url);
+ id_to_node_map[i->id] = node;
+ }
+ node->Reset(*i);
+
+ DCHECK(group_id_to_id_map.find(i->parent_group_id) !=
+ group_id_to_id_map.end());
+ history::StarID parent_id = group_id_to_id_map[i->parent_group_id];
+ BookmarkBarNode* parent = id_to_node_map[parent_id];
+ if (!parent) {
+ // Haven't encountered the parent yet, create it now.
+ parent = new BookmarkBarNode(NULL, GURL());
+ id_to_node_map[parent_id] = parent;
+ }
- // There must be root and bookmark bar nodes.
- if (!GetNodeByType(roots, StarredEntry::BOOKMARK_BAR))
- NOTREACHED() << "No bookmark bar folder in starred";
- else
- CheckVisualOrder(GetNodeByType(roots, StarredEntry::BOOKMARK_BAR));
-
- if (!GetNodeByType(roots, StarredEntry::OTHER))
- NOTREACHED() << "No other bookmarks folder in starred";
- else
- CheckVisualOrder(GetNodeByType(roots, StarredEntry::OTHER));
-
- // The only roots should be the bookmark bar and other nodes. Also count how
- // many bookmark bar and other folders exists.
- int bookmark_bar_count = 0;
- int other_folder_count = 0;
- for (std::set<StarredNode*>::const_iterator i = roots.begin();
- i != roots.end(); ++i) {
- if ((*i)->value.type == StarredEntry::USER_GROUP)
- NOTREACHED() << "Bookmark folder not in bookmark bar or other folders";
- else if ((*i)->value.type == StarredEntry::BOOKMARK_BAR)
- bookmark_bar_count++;
- else if ((*i)->value.type == StarredEntry::OTHER)
- other_folder_count++;
+ // Add the node to its parent. |entries| is ordered by parent then
+ // visual order so that we know we maintain visual order by always adding
+ // to the end.
+ parent->Add(parent->GetChildCount(), node);
}
- DCHECK(bookmark_bar_count == 1) << "Should be only one bookmark bar entry";
- DCHECK(other_folder_count == 1) << "Should be only one other folder entry";
- // There shouldn't be any folders with the same group id.
- if (!groups_with_duplicate_ids.empty())
- NOTREACHED() << "Bookmark folder with duplicate ids exist";
+ // Save to file.
+ BookmarkCodec encoder;
+ scoped_ptr<Value> encoded_bookmarks(
+ encoder.Encode(&bookmark_bar_node, &other_node));
+ std::string content;
+ JSONWriter::Write(encoded_bookmarks.get(), true, &content);
- // And all URLs should be parented.
- if (!unparented_urls.empty())
- NOTREACHED() << "Bookmarks not on the bookmark/'other folder' exist";
-
- if (!empty_url_ids.empty())
- NOTREACHED() << "Bookmarks with no corresponding URL exist";
-
- STLDeleteElements(&roots);
- STLDeleteElements(&unparented_urls);
-#endif NDEBUG
+ return (file_util::WriteFile(path, content.c_str(),
+ static_cast<int>(content.length())) != -1);
}
} // namespace history
diff --git a/chrome/browser/history/starred_url_database.h b/chrome/browser/history/starred_url_database.h
index d58571d..e7a774f 100644
--- a/chrome/browser/history/starred_url_database.h
+++ b/chrome/browser/history/starred_url_database.h
@@ -44,12 +44,9 @@ class SqliteStatementCache;
namespace history {
-// Encapsulates a URL database plus starred information.
-//
-// WARNING: many of the following methods allow you to update, delete or
-// insert starred entries specifying a visual order. These methods do NOT
-// adjust the visual order of surrounding entries. You must explicitly do
-// it yourself using AdjustStarredVisualOrder as appropriate.
+// Bookmarks were originally part of the url database, they have since been
+// moved to a separate file. This file exists purely for historical reasons and
+// contains just enough to allow migration.
class StarredURLDatabase : public URLDatabase {
public:
// Must call InitStarTable() AND any additional init functions provided by
@@ -57,87 +54,22 @@ class StarredURLDatabase : public URLDatabase {
StarredURLDatabase();
virtual ~StarredURLDatabase();
- // Returns the id of the starred entry. This does NOT return entry.id,
- // rather the database is queried for the id based on entry.url or
- // entry.group_id.
- StarID GetStarIDForEntry(const StarredEntry& entry);
-
- // Returns the internal star ID for the externally-generated group ID.
- StarID GetStarIDForGroupID(UIStarID group_id);
-
- // Gets the details for the specified star entry in entry.
- bool GetStarredEntry(StarID star_id, StarredEntry* entry);
-
- // Creates a starred entry with the requested information. The structure will
- // be updated with the ID of the newly created entry. The URL table will be
- // updated to point to the entry. The URL row will be created if it doesn't
- // exist.
- //
- // We currently only support one entry per URL. This URL should not already be
- // starred when calling this function or it will fail and will return 0.
- StarID CreateStarredEntry(StarredEntry* entry);
-
- // Returns starred entries.
- // This returns three different result types:
- // only_on_bookmark_bar == true: only those entries on the bookmark bar are
- // returned.
- // only_on_bookmark_bar == false and parent_id == 0: all starred
- // entries/groups.
- // otherwise only the direct children (groups and entries) of parent_id are
- // returned.
- bool GetStarredEntries(UIStarID parent_group_id,
- std::vector<StarredEntry>* entries);
-
- // Deletes a starred entry. This adjusts the visual order of all siblings
- // after the entry. The deleted entry(s) will be *appended* to
- // |*deleted_entries| (so delete can be called more than once with the same
- // list) and deleted URLs will additionally be added to the set.
- //
- // This function invokes DeleteStarredEntryImpl to do the actual work, which
- // recurses.
- void DeleteStarredEntry(StarID star_id,
- std::set<GURL>* unstarred_urls,
- std::vector<StarredEntry>* deleted_entries);
-
- // Implementation to update the database for UpdateStarredEntry. Returns true
- // on success. If successful, the parent_id, url_id, id and date_added fields
- // of the entry are reset from that of the database.
- bool UpdateStarredEntry(StarredEntry* entry);
-
- // Gets up to max_count starred entries of type URL adding them to entries.
- // The results are ordered by date added in descending order (most recent
- // first).
- void GetMostRecentStarredEntries(int max_count,
- std::vector<StarredEntry>* entries);
-
- // Gets the URLIDs for all starred entries of type URL whose title matches
- // the specified query.
- void GetURLsForTitlesMatching(const std::wstring& query,
- std::set<URLID>* ids);
-
- // Returns true if the starred table is in a sane state. If false, the starred
- // table is likely corrupt and shouldn't be used.
- bool is_starred_valid() const { return is_starred_valid_; }
-
- // Updates the URL ID for the given starred entry. This is used by the expirer
- // when URL IDs change. It can't use UpdateStarredEntry since that doesn't
- // set the URLID, and it does a bunch of other logic that we don't need.
- bool UpdateURLIDForStar(StarID star_id, URLID new_url_id);
-
protected:
// The unit tests poke our innards.
friend class HistoryTest;
+ friend class StarredURLDatabaseTest;
FRIEND_TEST(HistoryTest, CreateStarGroup);
+ // Writes bookmarks to the specified file.
+ bool MigrateBookmarksToFile(const std::wstring& path);
+
// Returns the database and statement cache for the functions in this
// interface. The decendent of this class implements these functions to
// return its objects.
virtual sqlite3* GetDB() = 0;
virtual SqliteStatementCache& GetStatementCache() = 0;
- // Creates the starred tables if necessary.
- bool InitStarTable();
-
+ private:
// Makes sure the starred table is in a sane state. This does the following:
// . Makes sure there is a bookmark bar and other nodes. If no bookmark bar
// node is found, the table is dropped and recreated.
@@ -155,17 +87,8 @@ class StarredURLDatabase : public URLDatabase {
// This should be invoked after migration.
bool EnsureStarredIntegrity();
- // Creates a starred entry with the specified parameters in the database.
- // Returns the newly created id, or 0 on failure.
- //
- // WARNING: Does not update the visual order.
- StarID CreateStarredEntryRow(URLID url_id,
- UIStarID group_id,
- UIStarID parent_group_id,
- const std::wstring& title,
- const Time& date_added,
- int visual_order,
- StarredEntry::Type type);
+ // Gets all the starred entries.
+ bool GetAllStarredEntries(std::vector<StarredEntry>* entries);
// Sets the title, parent_id, parent_group_id, visual_order and date_modifed
// of the specified star entry.
@@ -185,26 +108,39 @@ class StarredURLDatabase : public URLDatabase {
int start_visual_order,
int delta);
+ // Creates a starred entry with the specified parameters in the database.
+ // Returns the newly created id, or 0 on failure.
+ //
+ // WARNING: Does not update the visual order.
+ StarID CreateStarredEntryRow(URLID url_id,
+ UIStarID group_id,
+ UIStarID parent_group_id,
+ const std::wstring& title,
+ const Time& date_added,
+ int visual_order,
+ StarredEntry::Type type);
+
// Deletes the entry from the starred database base on the starred id (NOT
// the url id).
//
// WARNING: Does not update the visual order.
bool DeleteStarredEntryRow(StarID star_id);
- // Should the integrity of the starred table be checked on every mutation?
- // Default is true. Set to false when running tests that need to allow the
- // table to be in an invalid state while testing.
- bool check_starred_integrity_on_mutation_;
+ // Gets the details for the specified star entry in entry.
+ bool GetStarredEntry(StarID star_id, StarredEntry* entry);
+
+ // Creates a starred entry with the requested information. The structure will
+ // be updated with the ID of the newly created entry. The URL table will be
+ // updated to point to the entry. The URL row will be created if it doesn't
+ // exist.
+ //
+ // We currently only support one entry per URL. This URL should not already be
+ // starred when calling this function or it will fail and will return 0.
+ StarID CreateStarredEntry(StarredEntry* entry);
- private:
// Used when checking integrity of starred table.
typedef ChromeViews::TreeNodeWithValue<history::StarredEntry> StarredNode;
- // Implementation of DeleteStarredEntryImpl.
- void DeleteStarredEntryImpl(StarID star_id,
- std::set<GURL>* unstarred_urls,
- std::vector<StarredEntry>* deleted_entries);
-
// Returns the max group id, or 0 if there is an error.
UIStarID GetMaxGroupID();
@@ -262,24 +198,9 @@ class StarredURLDatabase : public URLDatabase {
// needs to be moved.
bool Move(StarredNode* source, StarredNode* new_parent);
- // Drops and recreates the starred table as well as marking all URLs as
- // unstarred. This is used as a last resort if the bookmarks table is
- // totally corrupt.
- bool RecreateStarredEntries();
-
- // Iterates through the children of node make sure the visual order matches
- // the order in node's children. DCHECKs if the order differs. This recurses.
- void CheckVisualOrder(StarredNode* node);
-
- // Makes sure the starred table is in a sane state, if not this DCHECKs.
- // This is invoked internally after any mutation to the starred table.
- //
- // This is a no-op in release builds.
- void CheckStarredIntegrity();
-
- // True if the starred table is valid. This is initialized in
- // EnsureStarredIntegrityImpl.
- bool is_starred_valid_;
+ // Does the work of migrating bookmarks to a temporary file that
+ // BookmarkStorage will read from.
+ bool MigrateBookmarksToFileImpl(const std::wstring& path);
DISALLOW_EVIL_CONSTRUCTORS(StarredURLDatabase);
};
diff --git a/chrome/browser/history/starred_url_database_unittest.cc b/chrome/browser/history/starred_url_database_unittest.cc
index aca91d9..c59c122 100644
--- a/chrome/browser/history/starred_url_database_unittest.cc
+++ b/chrome/browser/history/starred_url_database_unittest.cc
@@ -34,6 +34,7 @@
#include "base/string_util.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/starred_url_database.h"
+#include "chrome/common/chrome_paths.h"
#include "chrome/common/sqlite_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -51,18 +52,6 @@ class StarredURLDatabaseTest : public testing::Test,
EXPECT_TRUE(AddURL(row));
}
- StarredEntry GetStarredEntryByURL(const GURL& url) {
- std::vector<StarredEntry> starred;
- EXPECT_TRUE(GetStarredEntries(0, &starred));
- for (std::vector<StarredEntry>::iterator i = starred.begin();
- i != starred.end(); ++i) {
- if (i->url == url)
- return *i;
- }
- EXPECT_TRUE(false);
- return StarredEntry();
- }
-
void CompareEntryByID(const StarredEntry& entry) {
DCHECK(entry.id != 0);
StarredEntry db_value;
@@ -82,43 +71,20 @@ class StarredURLDatabaseTest : public testing::Test,
int GetStarredEntryCount() {
DCHECK(db_);
std::vector<StarredEntry> entries;
- GetStarredEntries(0, &entries);
+ GetAllStarredEntries(&entries);
return static_cast<int>(entries.size());
}
- bool GetURLStarred(const GURL& url) {
- URLRow row;
- if (GetRowForURL(url, &row))
- return row.starred();
- return false;
+ StarID CreateStarredEntry(StarredEntry* entry) {
+ return StarredURLDatabase::CreateStarredEntry(entry);
+ }
+
+ bool GetStarredEntry(StarID star_id, StarredEntry* entry) {
+ return StarredURLDatabase::GetStarredEntry(star_id, entry);
}
- void VerifyInitialState() {
- std::vector<StarredEntry> star_entries;
- EXPECT_TRUE(GetStarredEntries(0, &star_entries));
- EXPECT_EQ(2, star_entries.size());
-
- int bb_index = -1;
- size_t other_index = -1;
- if (star_entries[0].type == history::StarredEntry::BOOKMARK_BAR) {
- bb_index = 0;
- other_index = 1;
- } else {
- bb_index = 1;
- other_index = 0;
- }
- EXPECT_EQ(HistoryService::kBookmarkBarID, star_entries[bb_index].id);
- EXPECT_EQ(HistoryService::kBookmarkBarID, star_entries[bb_index].group_id);
- EXPECT_EQ(0, star_entries[bb_index].parent_group_id);
- EXPECT_EQ(StarredEntry::BOOKMARK_BAR, star_entries[bb_index].type);
-
- EXPECT_TRUE(star_entries[other_index].id != HistoryService::kBookmarkBarID
- && star_entries[other_index].id != 0);
- EXPECT_TRUE(star_entries[other_index].group_id !=
- HistoryService::kBookmarkBarID &&
- star_entries[other_index].group_id != 0);
- EXPECT_EQ(0, star_entries[other_index].parent_group_id);
- EXPECT_EQ(StarredEntry::OTHER, star_entries[other_index].type);
+ bool EnsureStarredIntegrity() {
+ return StarredURLDatabase::EnsureStarredIntegrity();
}
private:
@@ -129,13 +95,19 @@ class StarredURLDatabaseTest : public testing::Test,
db_file_.append(L"VisitTest.db");
file_util::Delete(db_file_, false);
+ // Copy db file over that contains starred table.
+ std::wstring old_history_path;
+ PathService::Get(chrome::DIR_TEST_DATA, &old_history_path);
+ file_util::AppendToPath(&old_history_path, L"bookmarks");
+ file_util::AppendToPath(&old_history_path, L"History_with_empty_starred");
+ file_util::CopyFile(old_history_path, db_file_);
+
EXPECT_EQ(SQLITE_OK, sqlite3_open(WideToUTF8(db_file_).c_str(), &db_));
statement_cache_ = new SqliteStatementCache(db_);
// Initialize the tables for this test.
CreateURLTable(false);
CreateMainURLIndex();
- InitStarTable();
EnsureStarredIntegrity();
}
void TearDown() {
@@ -159,307 +131,7 @@ class StarredURLDatabaseTest : public testing::Test,
//-----------------------------------------------------------------------------
-TEST_F(StarredURLDatabaseTest, CreateStarredEntryUnstarred) {
- StarredEntry entry;
- entry.title = L"blah";
- entry.date_added = Time::Now();
- entry.url = GURL("http://www.google.com");
- entry.parent_group_id = HistoryService::kBookmarkBarID;
-
- StarID id = CreateStarredEntry(&entry);
-
- EXPECT_NE(0, id);
- EXPECT_EQ(id, entry.id);
- CompareEntryByID(entry);
-}
-
-TEST_F(StarredURLDatabaseTest, UpdateStarredEntry) {
- const int initial_count = GetStarredEntryCount();
- StarredEntry entry;
- entry.title = L"blah";
- entry.date_added = Time::Now();
- entry.url = GURL("http://www.google.com");
- entry.parent_group_id = HistoryService::kBookmarkBarID;
-
- StarID id = CreateStarredEntry(&entry);
- EXPECT_NE(0, id);
- EXPECT_EQ(id, entry.id);
- CompareEntryByID(entry);
-
- // Now invoke create again, as the URL hasn't changed this should just
- // update the title.
- EXPECT_TRUE(UpdateStarredEntry(&entry));
- CompareEntryByID(entry);
-
- // There should only be two entries (one for the url we created, one for the
- // bookmark bar).
- EXPECT_EQ(initial_count + 1, GetStarredEntryCount());
-}
-
-TEST_F(StarredURLDatabaseTest, DeleteStarredGroup) {
- const int initial_count = GetStarredEntryCount();
- StarredEntry entry;
- entry.type = StarredEntry::USER_GROUP;
- entry.title = L"blah";
- entry.date_added = Time::Now();
- entry.group_id = 10;
- entry.parent_group_id = HistoryService::kBookmarkBarID;
-
- StarID id = CreateStarredEntry(&entry);
- EXPECT_NE(0, id);
- EXPECT_NE(HistoryService::kBookmarkBarID, id);
- CompareEntryByID(entry);
-
- EXPECT_EQ(initial_count + 1, GetStarredEntryCount());
-
- // Now delete it.
- std::set<GURL> unstarred_urls;
- std::vector<StarredEntry> deleted_entries;
- DeleteStarredEntry(entry.id, &unstarred_urls, &deleted_entries);
- ASSERT_EQ(0, unstarred_urls.size());
- ASSERT_EQ(1, deleted_entries.size());
- EXPECT_EQ(deleted_entries[0].id, id);
-
- // Should only have the bookmark bar.
- EXPECT_EQ(initial_count, GetStarredEntryCount());
-}
-
-TEST_F(StarredURLDatabaseTest, DeleteStarredGroupWithChildren) {
- const int initial_count = GetStarredEntryCount();
-
- StarredEntry entry;
- entry.type = StarredEntry::USER_GROUP;
- entry.title = L"blah";
- entry.date_added = Time::Now();
- entry.group_id = 10;
- entry.parent_group_id = HistoryService::kBookmarkBarID;
-
- StarID id = CreateStarredEntry(&entry);
- EXPECT_NE(0, id);
- EXPECT_NE(HistoryService::kBookmarkBarID, id);
- CompareEntryByID(entry);
-
- EXPECT_EQ(initial_count + 1, GetStarredEntryCount());
-
- // Create a child of the group.
- StarredEntry url_entry1;
- url_entry1.parent_group_id = entry.group_id;
- url_entry1.title = L"blah";
- url_entry1.date_added = Time::Now();
- url_entry1.url = GURL("http://www.google.com");
- StarID url_id1 = CreateStarredEntry(&url_entry1);
- EXPECT_NE(0, url_id1);
- CompareEntryByID(url_entry1);
-
- // Create a sibling of the group.
- StarredEntry url_entry2;
- url_entry2.parent_group_id = HistoryService::kBookmarkBarID;
- url_entry2.title = L"blah";
- url_entry2.date_added = Time::Now();
- url_entry2.url = GURL("http://www.google2.com");
- url_entry2.visual_order = 1;
- StarID url_id2 = CreateStarredEntry(&url_entry2);
- EXPECT_NE(0, url_id2);
- CompareEntryByID(url_entry2);
-
- EXPECT_EQ(initial_count + 3, GetStarredEntryCount());
-
- // Now delete the group, which should delete url_entry1 and shift down the
- // visual order of url_entry2.
- std::set<GURL> unstarred_urls;
- std::vector<StarredEntry> deleted_entries;
- DeleteStarredEntry(entry.id, &unstarred_urls, &deleted_entries);
- EXPECT_EQ(2, deleted_entries.size());
- EXPECT_EQ(1, unstarred_urls.size());
- EXPECT_TRUE((deleted_entries[0].id == id) || (deleted_entries[1].id == id));
- EXPECT_TRUE((deleted_entries[0].id == url_id1) ||
- (deleted_entries[1].id == url_id1));
-
- url_entry2.visual_order--;
- CompareEntryByID(url_entry2);
-
- // Should have the bookmark bar, and url_entry2.
- EXPECT_EQ(initial_count + 1, GetStarredEntryCount());
-}
-
-TEST_F(StarredURLDatabaseTest, InitialState) {
- VerifyInitialState();
-}
-
-TEST_F(StarredURLDatabaseTest, CreateStarGroup) {
- const int initial_count = GetStarredEntryCount();
- std::wstring title(L"title");
- Time time(Time::Now());
- int visual_order = 0;
-
- UIStarID ui_group_id = 10;
- UIStarID ui_parent_group_id = HistoryService::kBookmarkBarID;
-
- StarredEntry entry;
- entry.type = StarredEntry::USER_GROUP;
- entry.group_id = ui_group_id;
- entry.parent_group_id = ui_parent_group_id;
- entry.title = title;
- entry.date_added = time;
- entry.visual_order = visual_order;
- StarID group_id = CreateStarredEntry(&entry);
-
- EXPECT_NE(0, group_id);
- EXPECT_NE(HistoryService::kBookmarkBarID, group_id);
-
- EXPECT_EQ(group_id, GetStarIDForGroupID(ui_group_id));
-
- StarredEntry group_entry;
- EXPECT_TRUE(GetStarredEntry(group_id, &group_entry));
- EXPECT_EQ(ui_group_id, group_entry.group_id);
- EXPECT_EQ(ui_parent_group_id, group_entry.parent_group_id);
- EXPECT_TRUE(group_entry.title == title);
- // Don't use Time.== here as the conversion to time_t when writing to the db
- // is lossy.
- EXPECT_TRUE(group_entry.date_added.ToTimeT() == time.ToTimeT());
- EXPECT_EQ(visual_order, group_entry.visual_order);
-
- // Update the date modified.
- Time date_modified = Time::Now();
- entry.date_group_modified = date_modified;
- UpdateStarredEntry(&group_entry);
- EXPECT_TRUE(GetStarredEntry(group_id, &group_entry));
- EXPECT_TRUE(entry.date_group_modified.ToTimeT() == date_modified.ToTimeT());
-}
-
-TEST_F(StarredURLDatabaseTest, UpdateStarredEntryChangeVisualOrder) {
- const int initial_count = GetStarredEntryCount();
- GURL url1(L"http://google.com/1");
- GURL url2(L"http://google.com/2");
-
- // Star url1, making it a child of the bookmark bar.
- StarredEntry entry;
- entry.url = url1;
- entry.title = L"FOO";
- entry.parent_group_id = HistoryService::kBookmarkBarID;
- CreateStarredEntry(&entry);
-
- // Make sure it was created correctly.
- entry = GetStarredEntryByURL(url1);
- EXPECT_EQ(GetRowForURL(url1, NULL), entry.url_id);
- CompareEntryByID(entry);
-
- // Star url2, making it a child of the bookmark bar, placing it after url2.
- StarredEntry entry2;
- entry2.url = url2;
- entry2.visual_order = 1;
- entry2.title = std::wstring();
- entry2.parent_group_id = HistoryService::kBookmarkBarID;
- CreateStarredEntry(&entry2);
- entry2 = GetStarredEntryByURL(url2);
- EXPECT_EQ(GetRowForURL(url2, NULL), entry2.url_id);
- CompareEntryByID(entry2);
-
- // Move url2 to be before url1.
- entry2.visual_order = 0;
- UpdateStarredEntry(&entry2);
- CompareEntryByID(entry2);
-
- // URL1's visual order should have shifted by one to accommodate URL2.
- entry.visual_order = 1;
- CompareEntryByID(entry);
-
- // Now move URL1 to position 0, which will move url2 to position 1.
- entry.visual_order = 0;
- UpdateStarredEntry(&entry);
- CompareEntryByID(entry);
-
- entry2.visual_order = 1;
- CompareEntryByID(entry2);
-
- // Create a new group between url1 and url2.
- StarredEntry g_entry;
- g_entry.group_id = 10;
- g_entry.parent_group_id = HistoryService::kBookmarkBarID;
- g_entry.title = L"blah";
- g_entry.visual_order = 1;
- g_entry.date_added = Time::Now();
- g_entry.type = StarredEntry::USER_GROUP;
- g_entry.id = CreateStarredEntry(&g_entry);
- EXPECT_NE(0, g_entry.id);
- CompareEntryByID(g_entry);
-
- // URL2 should have shifted to position 2.
- entry2.visual_order = 2;
- CompareEntryByID(entry2);
-
- // Move url2 inside of group 1.
- entry2.visual_order = 0;
- entry2.parent_group_id = g_entry.group_id;
- UpdateStarredEntry(&entry2);
- CompareEntryByID(entry2);
-
- // Move url1 to be a child of group 1 at position 0.
- entry.parent_group_id = g_entry.group_id;
- entry.visual_order = 0;
- UpdateStarredEntry(&entry);
- CompareEntryByID(entry);
-
- // url2 should have moved to position 1.
- entry2.visual_order = 1;
- CompareEntryByID(entry2);
-
- // And the group should have shifted to position 0.
- g_entry.visual_order = 0;
- CompareEntryByID(g_entry);
-
- EXPECT_EQ(initial_count + 3, GetStarredEntryCount());
-
- // Delete the group, which should unstar url1 and url2.
- std::set<GURL> unstarred_urls;
- std::vector<StarredEntry> deleted_entries;
- DeleteStarredEntry(g_entry.id, &unstarred_urls, &deleted_entries);
- EXPECT_EQ(initial_count, GetStarredEntryCount());
- URLRow url_row;
- GetRowForURL(url1, &url_row);
- EXPECT_EQ(0, url_row.star_id());
- GetRowForURL(url2, &url_row);
- EXPECT_EQ(0, url_row.star_id());
-}
-
-TEST_F(StarredURLDatabaseTest, GetMostRecentStarredEntries) {
- // Initially there shouldn't be any entries (only the bookmark bar, which
- // isn't returned by GetMostRecentStarredEntries).
- std::vector<StarredEntry> starred_entries;
- GetMostRecentStarredEntries(10, &starred_entries);
- EXPECT_EQ(0, starred_entries.size());
-
- // Star url1.
- GURL url1(L"http://google.com/1");
- StarredEntry entry1;
- entry1.type = StarredEntry::URL;
- entry1.url = url1;
- entry1.parent_group_id = HistoryService::kBookmarkBarID;
- CreateStarredEntry(&entry1);
-
- // Get the recent ones.
- GetMostRecentStarredEntries(10, &starred_entries);
- ASSERT_EQ(1, starred_entries.size());
- EXPECT_TRUE(starred_entries[0].url == url1);
-
- // Add url2 and star it.
- GURL url2(L"http://google.com/2");
- StarredEntry entry2;
- entry2.type = StarredEntry::URL;
- entry2.url = url2;
- entry2.parent_group_id = HistoryService::kBookmarkBarID;
- CreateStarredEntry(&entry2);
-
- starred_entries.clear();
- GetMostRecentStarredEntries(10, &starred_entries);
- ASSERT_EQ(2, starred_entries.size());
- EXPECT_TRUE(starred_entries[0].url == url2);
- EXPECT_TRUE(starred_entries[1].url == url1);
-}
-
TEST_F(StarredURLDatabaseTest, FixOrphanedGroup) {
- check_starred_integrity_on_mutation_ = false;
-
const size_t initial_count = GetStarredEntryCount();
// Create a group that isn't parented to the other/bookmark folders.
@@ -482,8 +154,6 @@ TEST_F(StarredURLDatabaseTest, FixOrphanedGroup) {
}
TEST_F(StarredURLDatabaseTest, FixOrphanedBookmarks) {
- check_starred_integrity_on_mutation_ = false;
-
const size_t initial_count = GetStarredEntryCount();
// Create two bookmarks that aren't in a random folder no on the bookmark bar.
@@ -516,8 +186,6 @@ TEST_F(StarredURLDatabaseTest, FixOrphanedBookmarks) {
}
TEST_F(StarredURLDatabaseTest, FixGroupCycleDepth0) {
- check_starred_integrity_on_mutation_ = false;
-
const size_t initial_count = GetStarredEntryCount();
// Create a group that is parented to itself.
@@ -540,8 +208,6 @@ TEST_F(StarredURLDatabaseTest, FixGroupCycleDepth0) {
}
TEST_F(StarredURLDatabaseTest, FixGroupCycleDepth1) {
- check_starred_integrity_on_mutation_ = false;
-
const size_t initial_count = GetStarredEntryCount();
StarredEntry entry1;
@@ -574,8 +240,6 @@ TEST_F(StarredURLDatabaseTest, FixGroupCycleDepth1) {
}
TEST_F(StarredURLDatabaseTest, FixVisualOrder) {
- check_starred_integrity_on_mutation_ = false;
-
const size_t initial_count = GetStarredEntryCount();
// Star two urls.
@@ -607,29 +271,7 @@ TEST_F(StarredURLDatabaseTest, FixVisualOrder) {
CompareEntryByID(entry2);
}
-TEST_F(StarredURLDatabaseTest, RestoreOtherAndBookmarkBar) {
- std::vector<StarredEntry> entries;
- GetStarredEntries(0, &entries);
-
- check_starred_integrity_on_mutation_ = false;
-
- for (std::vector<StarredEntry>::iterator i = entries.begin();
- i != entries.end(); ++i) {
- if (i->type != StarredEntry::USER_GROUP) {
- // Use this directly, otherwise we assert trying to delete other/bookmark
- // bar.
- DeleteStarredEntryRow(i->id);
-
- ASSERT_TRUE(EnsureStarredIntegrity());
-
- VerifyInitialState();
- }
- }
-}
-
TEST_F(StarredURLDatabaseTest, FixDuplicateGroupIDs) {
- check_starred_integrity_on_mutation_ = false;
-
const size_t initial_count = GetStarredEntryCount();
// Create two groups with the same group id.
diff --git a/chrome/browser/history/text_database.h b/chrome/browser/history/text_database.h
index f04f8c0..4bcccd0 100644
--- a/chrome/browser/history/text_database.h
+++ b/chrome/browser/history/text_database.h
@@ -142,8 +142,6 @@ class TextDatabase {
// Querying ------------------------------------------------------------------
// Executes the given query. See QueryOptions for more info on input.
- // Note that the options.only_starred is ignored since this database does not
- // have access to star information.
//
// The results are appended to any existing ones in |*results|, and the first
// time considered for the output is in |first_time_searched|
diff --git a/chrome/browser/history/text_database_manager.h b/chrome/browser/history/text_database_manager.h
index 2506835..7685135b 100644
--- a/chrome/browser/history/text_database_manager.h
+++ b/chrome/browser/history/text_database_manager.h
@@ -165,8 +165,6 @@ class TextDatabaseManager {
void OptimizeChangedDatabases(const ChangeSet& change_set);
// Executes the given query. See QueryOptions for more info on input.
- // Note that the options.only_starred is ignored since this database does not
- // have access to star information.
//
// The results are filled into |results|, and the first time considered for
// the output is in |first_time_searched| (see QueryResults for more).
diff --git a/chrome/browser/history/url_database.cc b/chrome/browser/history/url_database.cc
index 0ce8072..899f04c 100644
--- a/chrome/browser/history/url_database.cc
+++ b/chrome/browser/history/url_database.cc
@@ -74,7 +74,6 @@ void URLDatabase::FillURLRow(SQLStatement& s, history::URLRow* i) {
i->last_visit_ = Time::FromInternalValue(s.column_int64(5));
i->hidden_ = s.column_int(6) != 0;
i->favicon_id_ = s.column_int64(7);
- i->star_id_ = s.column_int64(8);
}
bool URLDatabase::GetURLRow(URLID url_id, URLRow* info) {
@@ -115,7 +114,7 @@ bool URLDatabase::UpdateURLRow(URLID url_id,
const history::URLRow& info) {
SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
"UPDATE urls SET title=?,visit_count=?,typed_count=?,last_visit_time=?,"
- "hidden=?,starred_id=?,favicon_id=?"
+ "hidden=?,favicon_id=?"
"WHERE id=?");
if (!statement.is_valid())
return false;
@@ -125,9 +124,8 @@ bool URLDatabase::UpdateURLRow(URLID url_id,
statement->bind_int(2, info.typed_count());
statement->bind_int64(3, info.last_visit().ToInternalValue());
statement->bind_int(4, info.hidden() ? 1 : 0);
- statement->bind_int64(5, info.star_id());
- statement->bind_int64(6, info.favicon_id());
- statement->bind_int64(7, url_id);
+ statement->bind_int64(5, info.favicon_id());
+ statement->bind_int64(6, url_id);
return statement->step() == SQLITE_DONE;
}
@@ -139,8 +137,8 @@ URLID URLDatabase::AddURLInternal(const history::URLRow& info,
// invalid in the insert syntax.
#define ADDURL_COMMON_SUFFIX \
"(url,title,visit_count,typed_count,"\
- "last_visit_time,hidden,starred_id,favicon_id)"\
- "VALUES(?,?,?,?,?,?,?,?)"
+ "last_visit_time,hidden,favicon_id)"\
+ "VALUES(?,?,?,?,?,?,?)"
const char* statement_name;
const char* statement_sql;
if (is_temporary) {
@@ -163,8 +161,7 @@ URLID URLDatabase::AddURLInternal(const history::URLRow& info,
statement->bind_int(3, info.typed_count());
statement->bind_int64(4, info.last_visit().ToInternalValue());
statement->bind_int(5, info.hidden() ? 1 : 0);
- statement->bind_int64(6, info.star_id());
- statement->bind_int64(7, info.favicon_id());
+ statement->bind_int64(6, info.favicon_id());
if (statement->step() != SQLITE_DONE)
return 0;
@@ -250,21 +247,15 @@ bool URLDatabase::IsFavIconUsed(FavIconID favicon_id) {
}
void URLDatabase::AutocompleteForPrefix(const std::wstring& prefix,
- size_t max_results,
- std::vector<history::URLRow>* results) {
+ size_t max_results,
+ std::vector<history::URLRow>* results) {
+ // TODO(sky): this query should order by starred as the second order by
+ // clause.
results->clear();
-
- // NOTE: Sorting by "starred_id == 0" is subtle. First we do the comparison,
- // and, according to the SQLite docs, get a numeric result (all binary
- // operators except "||" result in a numeric value), which is either 1 or 0
- // (implied by documentation showing the results of various comparison
- // operations to always be 1 or 0). Now we sort ascending, meaning all 0s go
- // first -- so, all URLs where "starred_id == 0" is 0, i.e. all starred URLs.
SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
"SELECT" HISTORY_URL_ROW_FIELDS "FROM urls "
"WHERE url >= ? AND url < ? AND hidden = 0 "
- "ORDER BY typed_count DESC, starred_id == 0, visit_count DESC, "
- "last_visit_time DESC "
+ "ORDER BY typed_count DESC, visit_count DESC, last_visit_time DESC "
"LIMIT ?");
if (!statement.is_valid())
return;
@@ -443,6 +434,36 @@ bool URLDatabase::MigrateFromVersion11ToVersion12() {
return true;
}
+bool URLDatabase::DropStarredIDFromURLs() {
+ if (!DoesSqliteColumnExist(GetDB(), "urls", "starred_id", NULL))
+ return true; // urls is already updated, no need to continue.
+
+ // Create a temporary table to contain the new URLs table.
+ if (!CreateTemporaryURLTable()) {
+ NOTREACHED();
+ return false;
+ }
+
+ // Copy the contents.
+ const char* insert_statement =
+ "INSERT INTO temp_urls (id, url, title, visit_count, typed_count, "
+ "last_visit_time, hidden, favicon_id) "
+ "SELECT id, url, title, visit_count, typed_count, last_visit_time, "
+ "hidden, favicon_id FROM urls";
+ if (sqlite3_exec(GetDB(), insert_statement, NULL, NULL, NULL) != SQLITE_OK) {
+ NOTREACHED();
+ return false;
+ }
+
+ // Rename/commit the tmp table.
+ CommitTemporaryURLTable();
+
+ // This isn't created by CommitTemporaryURLTable.
+ CreateSupplimentaryURLIndices();
+
+ return true;
+}
+
bool URLDatabase::CreateURLTable(bool is_temporary) {
const char* name = is_temporary ? "temp_urls" : "urls";
if (DoesSqliteTableExist(GetDB(), name))
@@ -459,8 +480,7 @@ bool URLDatabase::CreateURLTable(bool is_temporary) {
"typed_count INTEGER DEFAULT 0 NOT NULL,"
"last_visit_time INTEGER NOT NULL,"
"hidden INTEGER DEFAULT 0 NOT NULL,"
- "favicon_id INTEGER DEFAULT 0 NOT NULL,"
- "starred_id INTEGER DEFAULT 0 NOT NULL)");
+ "favicon_id INTEGER DEFAULT 0 NOT NULL)");
return sqlite3_exec(GetDB(), sql.c_str(), NULL, NULL, NULL) == SQLITE_OK;
}
@@ -476,10 +496,6 @@ void URLDatabase::CreateSupplimentaryURLIndices() {
// Add a favicon index. This is useful when we delete urls.
sqlite3_exec(GetDB(), "CREATE INDEX urls_favicon_id_INDEX ON urls (favicon_id)",
NULL, NULL, NULL);
-
- // Index on starred_id.
- sqlite3_exec(GetDB(), "CREATE INDEX urls_starred_id_INDEX ON urls "
- "(starred_id)", NULL, NULL, NULL);
}
} // namespace history
diff --git a/chrome/browser/history/url_database.h b/chrome/browser/history/url_database.h
index 300c05b..f27c4b9 100644
--- a/chrome/browser/history/url_database.h
+++ b/chrome/browser/history/url_database.h
@@ -247,6 +247,8 @@ class URLDatabase {
int max_count,
std::vector<KeywordSearchTermVisit>* matches);
+ // Migration -----------------------------------------------------------------
+
// Do to a bug we were setting the favicon of about:blank. This forces
// about:blank to have no icon or title. Returns true on success, false if
// the favicon couldn't be updated.
@@ -263,6 +265,11 @@ class URLDatabase {
// fields following kURLRowFields.
static const int kNumURLRowFields;
+ // Drops the starred_id column from urls, returning true on success. This does
+ // nothing (and returns true) if the urls doesn't contain the starred_id
+ // column.
+ bool DropStarredIDFromURLs();
+
// Initialization functions. The indexing functions are separate from the
// table creation functions so the in-memory database and the temporary tables
// used when clearing history can populate the table and then create the
@@ -319,7 +326,7 @@ class URLDatabase {
// string dynamically anyway, use the constant, it will save space.
#define HISTORY_URL_ROW_FIELDS \
" urls.id, urls.url, urls.title, urls.visit_count, urls.typed_count, " \
- "urls.last_visit_time, urls.hidden, urls.favicon_id, urls.starred_id "
+ "urls.last_visit_time, urls.hidden, urls.favicon_id "
} // history
diff --git a/chrome/browser/history/url_database_unittest.cc b/chrome/browser/history/url_database_unittest.cc
index 7f2bdae..4983a5d 100644
--- a/chrome/browser/history/url_database_unittest.cc
+++ b/chrome/browser/history/url_database_unittest.cc
@@ -48,8 +48,7 @@ bool IsURLRowEqual(const URLRow& a,
a.visit_count() == b.visit_count() &&
a.typed_count() == b.typed_count() &&
a.last_visit() - b.last_visit() <= TimeDelta::FromSeconds(1) &&
- a.hidden() == b.hidden() &&
- a.starred() == b.starred();
+ a.hidden() == b.hidden();
}
class URLDatabaseTest : public testing::Test,
diff --git a/chrome/browser/history_model.cc b/chrome/browser/history_model.cc
index 80088d6..911d841 100644
--- a/chrome/browser/history_model.cc
+++ b/chrome/browser/history_model.cc
@@ -85,7 +85,12 @@ history::URLID HistoryModel::GetURLID(int index) {
}
bool HistoryModel::IsStarred(int index) {
- return results_[index].starred();
+ if (star_state_[index] == UNKNOWN) {
+ bool is_starred =
+ profile_->GetBookmarkBarModel()->IsBookmarked(GetURL(index));
+ star_state_[index] = is_starred ? STARRED : NOT_STARRED;
+ }
+ return (star_state_[index] == STARRED);
}
const Snippet& HistoryModel::GetSnippet(int index) {
@@ -138,7 +143,6 @@ void HistoryModel::InitVisitRequest(int depth) {
start_exploded.day_of_month = 1;
options.begin_time = Time::FromLocalExploded(start_exploded);
- options.only_starred = false;
options.max_count = max_total_results;
} else {
Time::Exploded exploded;
@@ -166,8 +170,6 @@ void HistoryModel::InitVisitRequest(int depth) {
}
options.begin_time = Time::FromLocalExploded(exploded);
- options.only_starred = false;
-
// Subtract off the number of pages we already got.
options.max_count = max_total_results - static_cast<int>(results_.size());
}
@@ -261,6 +263,8 @@ void HistoryModel::VisitedPagesQueryComplete(
is_search_results_ = !search_text_.empty();
+ if (changed)
+ star_state_.reset(new StarState[results_.size()]);
if (changed && observer_)
observer_->ModelChanged(true);
@@ -287,10 +291,8 @@ bool HistoryModel::UpdateStarredStateOfURL(const GURL& url, bool is_starred) {
size_t num_matches;
const size_t* match_indices = results_.MatchesForURL(url, &num_matches);
for (size_t i = 0; i < num_matches; i++) {
- // Update the view. (We don't care about the ID, just 0 or nonzero.)
- history::URLResult& result = results_[match_indices[i]];
- if (result.starred() != is_starred) {
- result.set_star_id(is_starred ? 1 : 0);
+ if (IsStarred(static_cast<int>(match_indices[i])) != is_starred) {
+ star_state_[match_indices[i]] = is_starred ? STARRED : NOT_STARRED;
changed = true;
}
}
diff --git a/chrome/browser/history_model.h b/chrome/browser/history_model.h
index 89e6e79..d5595ee 100644
--- a/chrome/browser/history_model.h
+++ b/chrome/browser/history_model.h
@@ -92,6 +92,18 @@ class HistoryModel : public BaseHistoryModel,
// Contents of the current query.
history::QueryResults results_;
+ // We lazily ask the BookmarkBarModel for whether a URL is starred. This
+ // enum gives the state of a particular entry.
+ enum StarState {
+ UNKNOWN = 0, // Indicates we haven't determined the state yet.
+ STARRED,
+ NOT_STARRED
+ };
+
+ // star_state_ has an entry for each element of results_ indicating whether
+ // the URL is starred.
+ scoped_array<StarState> star_state_;
+
// How many months back the current query has gone.
int search_depth_;
diff --git a/chrome/browser/views/bookmark_editor_view.cc b/chrome/browser/views/bookmark_editor_view.cc
index 8ae30ed..a4e9e8d 100644
--- a/chrome/browser/views/bookmark_editor_view.cc
+++ b/chrome/browser/views/bookmark_editor_view.cc
@@ -420,9 +420,9 @@ void BookmarkEditorView::ExpandAndSelect() {
tree_view_.ExpandAll();
BookmarkBarNode* to_select = bb_model_->GetNodeByURL(url_);
- history::UIStarID group_id_to_select =
- to_select ? to_select->GetParent()->GetGroupID() :
- bb_model_->GetParentForNewNodes()->GetGroupID();
+ int group_id_to_select =
+ to_select ? to_select->GetParent()->id() :
+ bb_model_->GetParentForNewNodes()->id();
DCHECK(group_id_to_select); // GetMostRecentParent should never return NULL.
BookmarkNode* b_node =
@@ -448,9 +448,9 @@ void BookmarkEditorView::CreateNodes(BookmarkBarNode* bb_node,
BookmarkEditorView::BookmarkNode* b_node) {
for (int i = 0; i < bb_node->GetChildCount(); ++i) {
BookmarkBarNode* child_bb_node = bb_node->GetChild(i);
- if (child_bb_node->GetType() != history::StarredEntry::URL) {
+ if (child_bb_node->is_folder()) {
BookmarkNode* new_b_node = new BookmarkNode(child_bb_node->GetTitle(),
- child_bb_node->GetGroupID());
+ child_bb_node->id());
b_node->Add(b_node->GetChildCount(), new_b_node);
CreateNodes(child_bb_node, new_b_node);
}
@@ -459,7 +459,7 @@ void BookmarkEditorView::CreateNodes(BookmarkBarNode* bb_node,
BookmarkEditorView::BookmarkNode* BookmarkEditorView::FindNodeWithID(
BookmarkEditorView::BookmarkNode* node,
- history::UIStarID id) {
+ int id) {
if (node->value == id)
return node;
for (int i = 0; i < node->GetChildCount(); ++i) {
@@ -556,8 +556,7 @@ void BookmarkEditorView::ApplyNameChangesAndCreateNewGroups(
// is the same).
for (int j = 0; j < bb_node->GetChildCount(); ++j) {
BookmarkBarNode* node = bb_node->GetChild(j);
- if (node->GetType() != history::StarredEntry::URL &&
- node->GetGroupID() == child_b_node->value) {
+ if (node->is_folder() && node->id() == child_b_node->value) {
child_bb_node = node;
break;
}
diff --git a/chrome/browser/views/bookmark_editor_view.h b/chrome/browser/views/bookmark_editor_view.h
index 8662b07..19bb4a1 100644
--- a/chrome/browser/views/bookmark_editor_view.h
+++ b/chrome/browser/views/bookmark_editor_view.h
@@ -135,7 +135,7 @@ class BookmarkEditorView : public ChromeViews::View,
private:
// Type of node in the tree.
- typedef ChromeViews::TreeNodeWithValue<history::UIStarID> BookmarkNode;
+ typedef ChromeViews::TreeNodeWithValue<int> BookmarkNode;
// Model for the TreeView. Trivial subclass that doesn't allow titles with
// empty strings.
@@ -197,8 +197,7 @@ class BookmarkEditorView : public ChromeViews::View,
BookmarkNode* b_node);
// Returns the node with the specified id, or NULL if one can't be found.
- BookmarkNode* FindNodeWithID(BookmarkEditorView::BookmarkNode* node,
- history::UIStarID id);
+ BookmarkNode* FindNodeWithID(BookmarkEditorView::BookmarkNode* node, int id);
// Invokes ApplyEdits with the selected node.
void ApplyEdits();