diff options
author | sky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-01 17:36:48 +0000 |
---|---|---|
committer | sky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-01 17:36:48 +0000 |
commit | 1fcb8b01fe855dde2485b82d620cdaecb580a3bd (patch) | |
tree | 5b626c7f5bb3f1272f1ef4c42b273dd54d4a1cc5 /chrome/browser | |
parent | 4bc09852839086aef45cea030b5973ea3f197e23 (diff) | |
download | chromium_src-1fcb8b01fe855dde2485b82d620cdaecb580a3bd.zip chromium_src-1fcb8b01fe855dde2485b82d620cdaecb580a3bd.tar.gz chromium_src-1fcb8b01fe855dde2485b82d620cdaecb580a3bd.tar.bz2 |
Adds a backend for the bookmarks bar that reads/writes to a JSON
file. These files aren't being built or used yet (though a test case
exists that is ifdef'd out).
BUG=1256202
TEST=none
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@248 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/bookmark_bar_model.h | 13 | ||||
-rw-r--r-- | chrome/browser/bookmark_bar_model_unittest.cc | 70 | ||||
-rw-r--r-- | chrome/browser/bookmark_codec.cc | 197 | ||||
-rw-r--r-- | chrome/browser/bookmark_codec.h | 80 | ||||
-rw-r--r-- | chrome/browser/bookmark_storage.cc | 185 | ||||
-rw-r--r-- | chrome/browser/bookmark_storage.h | 95 |
6 files changed, 640 insertions, 0 deletions
diff --git a/chrome/browser/bookmark_bar_model.h b/chrome/browser/bookmark_bar_model.h index edff1c7..b7e75f8 100644 --- a/chrome/browser/bookmark_bar_model.h +++ b/chrome/browser/bookmark_bar_model.h @@ -40,6 +40,7 @@ #include "skia/include/SkBitmap.h" class BookmarkBarModel; +class BookmarkCodec; class Profile; // BookmarkBarNode ------------------------------------------------------------ @@ -50,6 +51,7 @@ class Profile; // class BookmarkBarNode : public ChromeViews::TreeNode<BookmarkBarNode> { friend class BookmarkBarModel; + friend class BookmarkCodec; public: explicit BookmarkBarNode(BookmarkBarModel* model); @@ -64,6 +66,8 @@ class BookmarkBarNode : public ChromeViews::TreeNode<BookmarkBarNode> { 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 the type of this node. @@ -73,6 +77,7 @@ class BookmarkBarNode : public ChromeViews::TreeNode<BookmarkBarNode> { 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. @@ -81,6 +86,13 @@ class BookmarkBarNode : public ChromeViews::TreeNode<BookmarkBarNode> { favicon_ = SkBitmap(); } + // Returns the time the bookmark/group was added. + Time date_added() const { return date_added_; } + + // Returns the last time the group was modified. This is only maintained + // for folders (including the bookmark and other folder). + Time date_group_modified() const { return date_group_modified_; } + private: // Resets the properties of the node from the supplied entry. void Reset(const history::StarredEntry& entry); @@ -108,6 +120,7 @@ class BookmarkBarNode : public ChromeViews::TreeNode<BookmarkBarNode> { GURL url_; // Type of node. + // TODO(sky): bug 1256202, convert this into a type defined here. history::StarredEntry::Type type_; // Group ID. diff --git a/chrome/browser/bookmark_bar_model_unittest.cc b/chrome/browser/bookmark_bar_model_unittest.cc index efc94a7..5a95963 100644 --- a/chrome/browser/bookmark_bar_model_unittest.cc +++ b/chrome/browser/bookmark_bar_model_unittest.cc @@ -28,6 +28,9 @@ // 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/test/testing_profile.h" #include "chrome/views/tree_node_model.h" @@ -131,6 +134,31 @@ class BookmarkBarModelTest : public testing::Test, return GetMaxGroupID(model.root_node()); } + void AssertNodesEqual(BookmarkBarNode* expected, BookmarkBarNode* actual) { + ASSERT_TRUE(expected); + ASSERT_TRUE(actual); + EXPECT_EQ(expected->GetTitle(), actual->GetTitle()); + EXPECT_EQ(expected->GetType(), actual->GetType()); + EXPECT_TRUE(expected->date_added() == actual->date_added()); + if (expected->GetType() == history::StarredEntry::URL) { + EXPECT_EQ(expected->GetURL(), actual->GetURL()); + } else { + EXPECT_TRUE(expected->date_group_modified() == + actual->date_group_modified()); + ASSERT_EQ(expected->GetChildCount(), actual->GetChildCount()); + for (int i = 0; i < expected->GetChildCount(); ++i) + AssertNodesEqual(expected->GetChild(i), actual->GetChild(i)); + } + } + + void AssertModelsEqual(BookmarkBarModel* expected, + BookmarkBarModel* actual) { + AssertNodesEqual(expected->GetBookmarkBarNode(), + actual->GetBookmarkBarNode()); + AssertNodesEqual(expected->other_node(), + actual->other_node()); + } + BookmarkBarModel model; int moved_count; @@ -572,3 +600,45 @@ TEST_F(BookmarkBarModelTestWithProfile, CreateAndRestore) { VerifyModelMatchesNode(&other, bb_model_->other_node()); } } + +#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())); + + AssertModelsEqual(&expected_model, &actual_model); + } +} +#endif // USE_BOOKMARK_CODEC diff --git a/chrome/browser/bookmark_codec.cc b/chrome/browser/bookmark_codec.cc new file mode 100644 index 0000000..37f0ed0 --- /dev/null +++ b/chrome/browser/bookmark_codec.cc @@ -0,0 +1,197 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "chrome/browser/bookmark_codec.h" + +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/browser/bookmark_bar_model.h" +#include "googleurl/src/gurl.h" + +// Key names. +static const wchar_t* kRootsKey = L"roots"; +static const wchar_t* kRootFolderNameKey = L"root"; +static const wchar_t* kOtherBookmarFolderNameKey = L"other"; +static const wchar_t* kVersionKey = L"version"; +static const wchar_t* kTypeKey = L"type"; +static const wchar_t* kNameKey = L"name"; +static const wchar_t* kDateAddedKey = L"date_added"; +static const wchar_t* kURLKey = L"url"; +static const wchar_t* kDateModifiedKey = L"date_modified"; +static const wchar_t* kChildrenKey = L"children"; + +// Possible values for kTypeKey. +static const wchar_t* kTypeURL = L"url"; +static const wchar_t* kTypeFolder = L"folder"; + +// Current version of the file. +static const int kCurrentVersion = 1; + +Value* BookmarkCodec::Encode(BookmarkBarModel* model) { + DictionaryValue* roots = new DictionaryValue(); + roots->Set(kRootFolderNameKey, EncodeNode(model->GetBookmarkBarNode())); + roots->Set(kOtherBookmarFolderNameKey, EncodeNode(model->other_node())); + + DictionaryValue* main = new DictionaryValue(); + main->SetInteger(kVersionKey, kCurrentVersion); + main->Set(kRootsKey, roots); + return main; +} + +bool BookmarkCodec::Decode(BookmarkBarModel* model, const Value& value) { + if (value.GetType() != Value::TYPE_DICTIONARY) + return false; // Unexpected type. + + const DictionaryValue& d_value = static_cast<const DictionaryValue&>(value); + + int version; + if (!d_value.GetInteger(kVersionKey, &version) || version != kCurrentVersion) + return false; // Unknown version. + + Value* roots; + if (!d_value.Get(kRootsKey, &roots)) + return false; // No roots. + + if (roots->GetType() != Value::TYPE_DICTIONARY) + return false; // Invalid type for roots. + + DictionaryValue* roots_d_value = static_cast<DictionaryValue*>(roots); + Value* root_folder_value; + Value* other_folder_value; + if (!roots_d_value->Get(kRootFolderNameKey, &root_folder_value) || + root_folder_value->GetType() != Value::TYPE_DICTIONARY || + !roots_d_value->Get(kOtherBookmarFolderNameKey, &other_folder_value) || + other_folder_value->GetType() != Value::TYPE_DICTIONARY) + return false; // Invalid type for root folder and/or other folder. + + DecodeNode(model, *static_cast<DictionaryValue*>(root_folder_value), + model->GetBookmarkBarNode()); + DecodeNode(model, *static_cast<DictionaryValue*>(other_folder_value), + model->other_node()); + // Need to reset these as Decode sets the type to FOLDER. + model->GetBookmarkBarNode()->type_ = history::StarredEntry::BOOKMARK_BAR; + model->other_node()->type_ = history::StarredEntry::OTHER; + return true; +} + +Value* BookmarkCodec::EncodeNode(BookmarkBarNode* node) { + DictionaryValue* value = new DictionaryValue(); + value->SetString(kNameKey, node->GetTitle()); + value->SetString(kDateAddedKey, + Int64ToWString(node->date_added().ToInternalValue())); + if (node->GetType() == history::StarredEntry::URL) { + value->SetString(kTypeKey, kTypeURL); + value->SetString(kURLKey, + UTF8ToWide(node->GetURL().possibly_invalid_spec())); + } else { + value->SetString(kTypeKey, kTypeFolder); + value->SetString(kDateModifiedKey, + Int64ToWString(node->date_group_modified(). + ToInternalValue())); + + ListValue* child_values = new ListValue(); + value->Set(kChildrenKey, child_values); + for (int i = 0; i < node->GetChildCount(); ++i) + child_values->Append(EncodeNode(node->GetChild(i))); + } + return value; +} + +bool BookmarkCodec::DecodeChildren(BookmarkBarModel* model, + const ListValue& child_value_list, + BookmarkBarNode* parent) { + for (size_t i = 0; i < child_value_list.GetSize(); ++i) { + Value* child_value; + if (!child_value_list.Get(i, &child_value)) + return false; + + 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)) + return false; + } + return true; +} + +bool BookmarkCodec::DecodeNode(BookmarkBarModel* model, + const DictionaryValue& value, + BookmarkBarNode* node) { + 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)) + return false; + + if (type_string != kTypeURL && type_string != kTypeFolder) + return false; // Unknown type. + + if (type_string == kTypeURL) { + std::wstring url_string; + if (!value.GetString(kURLKey, &url_string)) + return false; + node->SetURL(GURL(url_string)); + 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)) + return false; + + 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); + return false; + } + } + + return true; +} diff --git a/chrome/browser/bookmark_codec.h b/chrome/browser/bookmark_codec.h new file mode 100644 index 0000000..ffe51c2 --- /dev/null +++ b/chrome/browser/bookmark_codec.h @@ -0,0 +1,80 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// BookmarkCodec is responsible for encoding and decoding the BookmarkBarModel +// into JSON values. The encoded values are written to disk via the +// BookmarkService. + +#ifndef CHROME_BROWSER_BOOKMARK_CODEC_H_ + +#include "base/basictypes.h" + +class BookmarkBarModel; +class BookmarkBarNode; +class DictionaryValue; +class ListValue; +class Value; + +// BookmarkCodec is responsible for encoding/decoding bookmarks into JSON +// values. BookmarkCodec is used by BookmarkService. + +class BookmarkCodec { + public: + BookmarkCodec() {} + + // Encodes the model to a JSON value. It's up to the caller to delete the + // returned object. + Value* Encode(BookmarkBarModel* model); + + // 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 + // nodes. + bool Decode(BookmarkBarModel* model, const Value& value); + + private: + // Encodes node and all its children into a Value object and returns it. + // The caller takes ownership of the returned object. + Value* EncodeNode(BookmarkBarNode* node); + + // Decodes the children of the specified node. Returns true on success. + bool DecodeChildren(BookmarkBarModel* model, + const ListValue& child_value_list, + BookmarkBarNode* parent); + + // Decodes the supplied node from the supplied value. Child nodes are + // created appropriately by way of DecodeChildren. + bool DecodeNode(BookmarkBarModel* model, + const DictionaryValue& value, + BookmarkBarNode* node); + + DISALLOW_COPY_AND_ASSIGN(BookmarkCodec); +}; + +#endif // CHROME_BROWSER_BOOKMARK_CODEC_H_ diff --git a/chrome/browser/bookmark_storage.cc b/chrome/browser/bookmark_storage.cc new file mode 100644 index 0000000..e1fed29 --- /dev/null +++ b/chrome/browser/bookmark_storage.cc @@ -0,0 +1,185 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// 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). + +#include "chrome/browser/bookmark_storage.h" + +#include "base/file_util.h" +#include "base/json_writer.h" +#include "base/message_loop.h" +#include "chrome/browser/bookmark_bar_model.h" +#include "chrome/browser/bookmark_codec.h" +#include "chrome/browser/profile.h" +#include "chrome/common/json_value_serializer.h" + +namespace { + +// Extension used for backup files (copy of main file created during startup). +const wchar_t* const kBackupExtension = L"bak"; + +// Extension for the temporary file. We write to the temp file than move to +// 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)); +} + +} // namespace + +BookmarkStorage::BookmarkStorage(Profile* profile, BookmarkBarModel* model) + : model_(model), +#pragma warning(suppress: 4355) // Okay to pass "this" here. + save_factory_(this) { + std::wstring path = profile->GetPath(); + file_util::AppendToPath(&path, kBookmarksFileName); + backend_ = new BookmarkStorageBackend(path); +} + +void BookmarkStorage::LoadBookmarks() { + backend_thread()->message_loop()->PostTask( + FROM_HERE, + NewRunnableMethod(backend_.get(), &BookmarkStorageBackend::Read, + scoped_refptr<BookmarkStorage>(this), + MessageLoop::current())); +} + +void BookmarkStorage::ScheduleSave() { + if (save_factory_.empty()) { + MessageLoop::current()->PostDelayedTask( + FROM_HERE, save_factory_.NewRunnableMethod(&BookmarkStorage::SaveNow), + kSaveDelayMS); + } +} + +void BookmarkStorage::BookmarkModelDeleted() { + if (!save_factory_.empty()) { + // There's a pending save. We need to save now as otherwise by the time + // SaveNow is invoked the model is gone. + save_factory_.RevokeAll(); + SaveNow(); + } + model_ = NULL; +} + +void BookmarkStorage::LoadedBookmarks(Value* root_value) { + scoped_ptr<Value> value_ref(root_value); + + if (model_) { + if (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. + } +} + +void BookmarkStorage::SaveNow() { + if (!model_ || !model_->IsLoaded()) { + // We should only get here if we have a valid model and it's finished + // loading. + NOTREACHED(); + return; + } + + 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)); +} diff --git a/chrome/browser/bookmark_storage.h b/chrome/browser/bookmark_storage.h new file mode 100644 index 0000000..8ba00d0 --- /dev/null +++ b/chrome/browser/bookmark_storage.h @@ -0,0 +1,95 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (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_ + +#include "base/ref_counted.h" +#include "base/task.h" +#include "chrome/browser/browser_process.h" + +class BookmarkBarModel; +class Profile; +class Value; + +namespace { +class BookmarkStorageBackend; +} + +class BookmarkStorage : public base::RefCountedThreadSafe<BookmarkStorage> { + friend class BookmarkStorageBackend; + + public: + // 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(); + + // Schedules saving the bookmark bar model to disk. + void ScheduleSave(); + + // Notification the bookmark bar model is going to be deleted. If there is + // a pending save, it is saved immediately. + void BookmarkModelDeleted(); + + private: + // Callback from backend with the results of the bookmark file. + void LoadedBookmarks(Value* root_value); + + // 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(); } + + // The model. The model is NULL once BookmarkModelDeleted has been invoked. + BookmarkBarModel* model_; + + // Used to delay saves. + ScopedRunnableMethodFactory<BookmarkStorage> save_factory_; + + // The backend handles actual reading/writing to disk. + scoped_refptr<BookmarkStorageBackend> backend_; + + DISALLOW_COPY_AND_ASSIGN(BookmarkStorage); +}; + +#endif // CHROME_BROWSER_BOOKMARK_STORAGE_H_ |