// Copyright (c) 2009 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/cookies_tree_model.h" #include #include #include #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "app/table_model_observer.h" #include "app/tree_node_model.h" #include "base/linked_ptr.h" #include "base/string_util.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/profile.h" #include "grit/app_resources.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "net/base/cookie_monster.h" #include "net/url_request/url_request_context.h" #include "third_party/skia/include/core/SkBitmap.h" /////////////////////////////////////////////////////////////////////////////// // CookieTreeNode, public: void CookieTreeNode::DeleteStoredObjects() { std::for_each(children().begin(), children().end(), std::mem_fun(&CookieTreeNode::DeleteStoredObjects)); } CookiesTreeModel* CookieTreeNode::GetModel() const { if (GetParent()) return GetParent()->GetModel(); else return NULL; } /////////////////////////////////////////////////////////////////////////////// // CookieTreeCookieNode, public: CookieTreeCookieNode::CookieTreeCookieNode( net::CookieMonster::CookieListPair* cookie) : CookieTreeNode(UTF8ToWide(cookie->second.Name())), cookie_(cookie) { } void CookieTreeCookieNode::DeleteStoredObjects() { GetModel()->DeleteCookie(*cookie_); } namespace { // comparison functor, for use in CookieTreeRootNode class OriginNodeComparator { public: bool operator() (const CookieTreeNode* lhs, const CookieTreeNode* rhs) { return (lhs->GetTitle() < rhs->GetTitle()); } }; } // namespace /////////////////////////////////////////////////////////////////////////////// // CookieTreeRootNode, public: CookieTreeOriginNode* CookieTreeRootNode::GetOrCreateOriginNode( const std::wstring& origin) { // Strip the trailing dot if it exists. std::wstring rewritten_origin = origin; if (origin.length() >= 1 && origin[0] == '.') rewritten_origin = origin.substr(1); CookieTreeOriginNode rewritten_origin_node(rewritten_origin); // First see if there is an existing match. std::vector::iterator origin_node_iterator = lower_bound(children().begin(), children().end(), &rewritten_origin_node, OriginNodeComparator()); if (origin_node_iterator != children().end() && rewritten_origin == (*origin_node_iterator)->GetTitle()) return static_cast(*origin_node_iterator); // Node doesn't exist, create a new one and insert it into the (ordered) // children. CookieTreeOriginNode* retval = new CookieTreeOriginNode(rewritten_origin); DCHECK(model_); model_->Add(this, (origin_node_iterator - children().begin()), retval); return retval; } /////////////////////////////////////////////////////////////////////////////// // CookieTreeOriginNode, public: CookieTreeCookiesNode* CookieTreeOriginNode::GetOrCreateCookiesNode() { if (cookies_child_) return cookies_child_; // need to make a Cookies node, add it to the tree, and return it CookieTreeCookiesNode* retval = new CookieTreeCookiesNode; GetModel()->Add(this, 0, retval); cookies_child_ = retval; return retval; } /////////////////////////////////////////////////////////////////////////////// // CookieTreeCookiesNode, public: CookieTreeCookiesNode::CookieTreeCookiesNode() : CookieTreeNode(l10n_util::GetString(IDS_COOKIES_COOKIES)) {} void CookieTreeCookiesNode::AddCookieNode( CookieTreeCookieNode* new_child) { std::vector::iterator cookie_iterator = lower_bound(children().begin(), children().end(), new_child, CookieTreeCookieNode::CookieNodeComparator()); GetModel()->Add(this, (cookie_iterator - children().begin()), new_child); } /////////////////////////////////////////////////////////////////////////////// // CookieTreeCookieNode, private bool CookieTreeCookieNode::CookieNodeComparator::operator() ( const CookieTreeNode* lhs, const CookieTreeNode* rhs) { return (static_cast(lhs)-> cookie_->second.Name() < static_cast(rhs)-> cookie_->second.Name()); } /////////////////////////////////////////////////////////////////////////////// // CookiesTreeModel, public: CookiesTreeModel::CookiesTreeModel(Profile* profile) : ALLOW_THIS_IN_INITIALIZER_LIST(TreeNodeModel( new CookieTreeRootNode(this))), profile_(profile) { LoadCookies(); } /////////////////////////////////////////////////////////////////////////////// // CookiesTreeModel, TreeModel methods (public): // TreeModel methods: // Returns the set of icons for the nodes in the tree. You only need override // this if you don't want to use the default folder icons. void CookiesTreeModel::GetIcons(std::vector* icons) { icons->push_back(*ResourceBundle::GetSharedInstance().GetBitmapNamed( IDR_DEFAULT_FAVICON)); icons->push_back(*ResourceBundle::GetSharedInstance().GetBitmapNamed( IDR_COOKIE_ICON)); } // Returns the index of the icon to use for |node|. Return -1 to use the // default icon. The index is relative to the list of icons returned from // GetIcons. int CookiesTreeModel::GetIconIndex(TreeModelNode* node) { CookieTreeNode* ct_node = static_cast(node); switch (ct_node->GetDetailedInfo().node_type) { case CookieTreeNode::DetailedInfo::TYPE_ORIGIN: return ORIGIN; break; case CookieTreeNode::DetailedInfo::TYPE_COOKIE: return COOKIE; break; default: return -1; } } void CookiesTreeModel::LoadCookies() { // mmargh mmargh mmargh! // Since we are running on the UI thread don't call GetURLRequestContext(). net::CookieMonster* cookie_monster = profile_->GetRequestContext()->GetCookieStore()->GetCookieMonster(); all_cookies_ = cookie_monster->GetAllCookies(); CookieTreeRootNode* root = static_cast(GetRoot()); for (CookieList::iterator it = all_cookies_.begin(); it != all_cookies_.end(); ++it) { // Get the origin cookie CookieTreeOriginNode* origin = root->GetOrCreateOriginNode(UTF8ToWide(it->first)); CookieTreeCookiesNode* cookies_node = origin->GetOrCreateCookiesNode(); CookieTreeCookieNode* new_cookie = new CookieTreeCookieNode(&*it); cookies_node->AddCookieNode(new_cookie); } } void CookiesTreeModel::DeleteCookie( const net::CookieMonster::CookieListPair& cookie) { // notify CookieMonster that we should delete this cookie // Since we are running on the UI thread don't call GetURLRequestContext(). net::CookieMonster* monster = profile_->GetRequestContext()->GetCookieStore()->GetCookieMonster(); // We have stored a copy of all the cookies in the model, and our model is // never re-calculated. Thus, we just need to delete the nodes from our // model, and tell CookieMonster to delete the cookies. We can keep the // vector storing the cookies in-tact and not delete from there (that would // invalidate our pointers), and the fact that it contains semi out-of-date // data is not problematic as we don't re-build the model based on that. monster->DeleteCookie(cookie.first, cookie.second, true); } void CookiesTreeModel::DeleteAllCookies() { CookieTreeNode* root = GetRoot(); root->DeleteStoredObjects(); int num_children = root->GetChildCount(); for (int i = num_children - 1; i >= 0; --i) { delete Remove(root, i); } LoadCookies(); NotifyObserverTreeNodeChanged(root); } void CookiesTreeModel::DeleteCookieNode(CookieTreeNode* cookie_node) { cookie_node->DeleteStoredObjects(); // find the parent and index CookieTreeNode* parent_node = cookie_node->GetParent(); int cookie_node_index = parent_node->IndexOfChild(cookie_node); delete Remove(parent_node, cookie_node_index); }