// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/bookmarks/bookmark_table_model.h" #include #include "base/string_util.h" #include "base/time.h" #include "base/time_format.h" #include "chrome/app/theme/theme_resources.h" #include "chrome/common/resource_bundle.h" #include "googleurl/src/gurl.h" #include "generated_resources.h" namespace { // Number of bookmarks shown in recently bookmarked. const int kRecentlyBookmarkedCount = 50; // FolderBookmarkTableModel ---------------------------------------------------- class FolderBookmarkTableModel : public BookmarkTableModel { public: FolderBookmarkTableModel(BookmarkModel* model, BookmarkNode* root_node) : BookmarkTableModel(model), root_node_(root_node) { } virtual int RowCount() { return root_node_ ? root_node_->GetChildCount() : 0; } virtual BookmarkNode* GetNodeForRow(int row) { DCHECK(root_node_); return root_node_->GetChild(row); } virtual void BookmarkNodeMoved(BookmarkModel* model, BookmarkNode* old_parent, int old_index, BookmarkNode* new_parent, int new_index) { if (observer() && (old_parent == root_node_ || new_parent == root_node_)) observer()->OnModelChanged(); } virtual void BookmarkNodeAdded(BookmarkModel* model, BookmarkNode* parent, int index) { if (root_node_ == parent && observer()) observer()->OnItemsAdded(index, 1); } virtual void BookmarkNodeRemoved(BookmarkModel* model, BookmarkNode* parent, int index, BookmarkNode* node) { if (root_node_->HasAncestor(node)) { // We, our one of our ancestors was removed. root_node_ = NULL; if (observer()) observer()->OnModelChanged(); return; } if (root_node_ == parent && observer()) observer()->OnItemsRemoved(index, 1); } virtual void BookmarkNodeChanged(BookmarkModel* model, BookmarkNode* node) { NotifyChanged(node); } virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model, BookmarkNode* node) { NotifyChanged(node); } private: void NotifyChanged(BookmarkNode* node) { if (node->GetParent() == root_node_ && observer()) observer()->OnItemsChanged(node->GetParent()->IndexOfChild(node), 1); } // The node we're showing the children of. This is set to NULL if the node // (or one of its ancestors) is removed from the model. BookmarkNode* root_node_; DISALLOW_COPY_AND_ASSIGN(FolderBookmarkTableModel); }; // VectorBackedBookmarkTableModel ---------------------------------------------- class VectorBackedBookmarkTableModel : public BookmarkTableModel { public: explicit VectorBackedBookmarkTableModel(BookmarkModel* model) : BookmarkTableModel(model) { } virtual BookmarkNode* GetNodeForRow(int row) { return nodes_[row]; } virtual int RowCount() { return static_cast(nodes_.size()); } virtual void BookmarkNodeMoved(BookmarkModel* model, BookmarkNode* old_parent, int old_index, BookmarkNode* new_parent, int new_index) { NotifyObserverOfChange(new_parent->GetChild(new_index)); } virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model, BookmarkNode* node) { NotifyObserverOfChange(node); } virtual void BookmarkNodeChanged(BookmarkModel* model, BookmarkNode* node) { NotifyObserverOfChange(node); } protected: void NotifyObserverOfChange(BookmarkNode* node) { if (!observer()) return; int index = IndexOfNode(node); if (index != -1) observer()->OnItemsChanged(index, 1); } typedef std::vector Nodes; Nodes nodes_; private: DISALLOW_COPY_AND_ASSIGN(VectorBackedBookmarkTableModel); }; // RecentlyBookmarkedTableModel ------------------------------------------------ class RecentlyBookmarkedTableModel : public VectorBackedBookmarkTableModel { public: explicit RecentlyBookmarkedTableModel(BookmarkModel* model) : VectorBackedBookmarkTableModel(model) { UpdateRecentlyBookmarked(); } virtual void BookmarkNodeAdded(BookmarkModel* model, BookmarkNode* parent, int index) { if (parent->GetChild(index)->is_url()) UpdateRecentlyBookmarked(); } virtual void BookmarkNodeRemoved(BookmarkModel* model, BookmarkNode* parent, int old_index, BookmarkNode* old_node) { if (old_node->is_url()) UpdateRecentlyBookmarked(); } private: void UpdateRecentlyBookmarked() { nodes_.clear(); model()->GetMostRecentlyAddedEntries(kRecentlyBookmarkedCount, &nodes_); if (observer()) observer()->OnModelChanged(); } DISALLOW_COPY_AND_ASSIGN(RecentlyBookmarkedTableModel); }; // BookmarkSearchTableModel ---------------------------------------------------- class BookmarkSearchTableModel : public VectorBackedBookmarkTableModel { public: BookmarkSearchTableModel(BookmarkModel* model, const std::wstring& search_text) : VectorBackedBookmarkTableModel(model), search_text_(search_text) { std::vector matches; model->GetBookmarksMatchingText(search_text, std::numeric_limits::max(), &matches); for (size_t i = 0; i < matches.size(); ++i) nodes_.push_back(matches[i].node); } virtual void BookmarkNodeAdded(BookmarkModel* model, BookmarkNode* parent, int index) { BookmarkNode* node = parent->GetChild(index); if (model->DoesBookmarkMatchText(search_text_, node)) { nodes_.push_back(node); if (observer()) observer()->OnItemsAdded(static_cast(nodes_.size() - 1), 1); } } virtual void BookmarkNodeRemoved(BookmarkModel* model, BookmarkNode* parent, int index, BookmarkNode* node) { int internal_index = IndexOfNode(node); if (internal_index == -1) return; nodes_.erase(nodes_.begin() + static_cast(internal_index)); if (observer()) observer()->OnItemsRemoved(internal_index, 1); } private: const std::wstring search_text_; DISALLOW_COPY_AND_ASSIGN(BookmarkSearchTableModel); }; } // namespace // BookmarkTableModel ---------------------------------------------------------- // static BookmarkTableModel* BookmarkTableModel::CreateRecentlyBookmarkedModel( BookmarkModel* model) { return new RecentlyBookmarkedTableModel(model); } // static BookmarkTableModel* BookmarkTableModel::CreateBookmarkTableModelForFolder( BookmarkModel* model, BookmarkNode* node) { return new FolderBookmarkTableModel(model, node); } // static BookmarkTableModel* BookmarkTableModel::CreateSearchTableModel( BookmarkModel* model, const std::wstring& text) { return new BookmarkSearchTableModel(model, text); } BookmarkTableModel::BookmarkTableModel(BookmarkModel* model) : model_(model), observer_(NULL) { model_->AddObserver(this); } BookmarkTableModel::~BookmarkTableModel() { if (model_) model_->RemoveObserver(this); } std::wstring BookmarkTableModel::GetText(int row, int column_id) { BookmarkNode* node = GetNodeForRow(row); switch (column_id) { case IDS_BOOKMARK_TABLE_TITLE: return node->GetTitle(); case IDS_BOOKMARK_TABLE_URL: return node->is_url() ? UTF8ToWide(node->GetURL().spec()) : std::wstring(); case IDS_BOOKMARK_TABLE_PATH: { std::wstring path; BuildPath(node->GetParent(), &path); return path; } } NOTREACHED(); return std::wstring(); } SkBitmap BookmarkTableModel::GetIcon(int row) { static SkBitmap* folder_icon = ResourceBundle::GetSharedInstance(). GetBitmapNamed(IDR_BOOKMARK_BAR_FOLDER); static SkBitmap* default_icon = ResourceBundle::GetSharedInstance(). GetBitmapNamed(IDR_DEFAULT_FAVICON); BookmarkNode* node = GetNodeForRow(row); if (node->is_folder()) return *folder_icon; if (node->GetFavIcon().empty()) return *default_icon; return node->GetFavIcon(); } void BookmarkTableModel::BookmarkModelBeingDeleted(BookmarkModel* model) { model_->RemoveObserver(this); model_ = NULL; } int BookmarkTableModel::IndexOfNode(BookmarkNode* node) { for (int i = RowCount() - 1; i >= 0; --i) { if (GetNodeForRow(i) == node) return i; } return -1; } void BookmarkTableModel::BuildPath(BookmarkNode* node, std::wstring* path) { if (!node) { NOTREACHED(); return; } if (node == model()->GetBookmarkBarNode()) { *path = l10n_util::GetString(IDS_BOOKMARK_TABLE_BOOKMARK_BAR_PATH); return; } if (node == model()->other_node()) { *path = l10n_util::GetString(IDS_BOOKMARK_TABLE_OTHER_BOOKMARKS_PATH); return; } BuildPath(node->GetParent(), path); path->append(l10n_util::GetString(IDS_BOOKMARK_TABLE_PATH_SEPARATOR)); path->append(node->GetTitle()); }