recently_used_folders_combo_model.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h" 6 7#include "chrome/browser/bookmarks/bookmark_model.h" 8#include "chrome/browser/bookmarks/bookmark_utils.h" 9#include "content/public/browser/user_metrics.h" 10#include "grit/generated_resources.h" 11#include "ui/base/l10n/l10n_util.h" 12#include "ui/base/models/combobox_model_observer.h" 13 14namespace { 15 16// Max number of most recently used folders. 17const size_t kMaxMRUFolders = 5; 18 19} // namespace 20 21struct RecentlyUsedFoldersComboModel::Item { 22 enum Type { 23 TYPE_NODE, 24 TYPE_SEPARATOR, 25 TYPE_CHOOSE_ANOTHER_FOLDER 26 }; 27 28 Item(const BookmarkNode* node, Type type); 29 ~Item(); 30 31 bool operator==(const Item& item) const; 32 33 const BookmarkNode* node; 34 Type type; 35}; 36 37RecentlyUsedFoldersComboModel::Item::Item(const BookmarkNode* node, 38 Type type) 39 : node(node), 40 type(type) { 41} 42 43RecentlyUsedFoldersComboModel::Item::~Item() {} 44 45bool RecentlyUsedFoldersComboModel::Item::operator==(const Item& item) const { 46 return item.node == node && item.type == type; 47} 48 49RecentlyUsedFoldersComboModel::RecentlyUsedFoldersComboModel( 50 BookmarkModel* model, 51 const BookmarkNode* node) 52 : bookmark_model_(model), 53 node_parent_index_(0) { 54 bookmark_model_->AddObserver(this); 55 // Use + 2 to account for bookmark bar and other node. 56 std::vector<const BookmarkNode*> nodes = 57 bookmark_utils::GetMostRecentlyModifiedFolders(model, kMaxMRUFolders + 2); 58 59 for (size_t i = 0; i < nodes.size(); ++i) 60 items_.push_back(Item(nodes[i], Item::TYPE_NODE)); 61 62 // We special case the placement of these, so remove them from the list, then 63 // fix up the order. 64 RemoveNode(model->bookmark_bar_node()); 65 RemoveNode(model->mobile_node()); 66 RemoveNode(model->other_node()); 67 RemoveNode(node->parent()); 68 69 // Make the parent the first item, unless it's a permanent node, which is 70 // added below. 71 if (!model->is_permanent_node(node->parent())) 72 items_.insert(items_.begin(), Item(node->parent(), Item::TYPE_NODE)); 73 74 // Make sure we only have kMaxMRUFolders in the first chunk. 75 if (items_.size() > kMaxMRUFolders) 76 items_.erase(items_.begin() + kMaxMRUFolders, items_.end()); 77 78 // And put the bookmark bar and other nodes at the end of the list. 79 items_.push_back(Item(model->bookmark_bar_node(), Item::TYPE_NODE)); 80 items_.push_back(Item(model->other_node(), Item::TYPE_NODE)); 81 if (model->mobile_node()->IsVisible()) 82 items_.push_back(Item(model->mobile_node(), Item::TYPE_NODE)); 83 items_.push_back(Item(NULL, Item::TYPE_SEPARATOR)); 84 items_.push_back(Item(NULL, Item::TYPE_CHOOSE_ANOTHER_FOLDER)); 85 86 std::vector<Item>::iterator it = std::find(items_.begin(), 87 items_.end(), 88 Item(node->parent(), 89 Item::TYPE_NODE)); 90 node_parent_index_ = static_cast<int>(it - items_.begin()); 91} 92 93RecentlyUsedFoldersComboModel::~RecentlyUsedFoldersComboModel() { 94 bookmark_model_->RemoveObserver(this); 95} 96 97int RecentlyUsedFoldersComboModel::GetItemCount() const { 98 return static_cast<int>(items_.size()); 99} 100 101base::string16 RecentlyUsedFoldersComboModel::GetItemAt(int index) { 102 switch (items_[index].type) { 103 case Item::TYPE_NODE: 104 return items_[index].node->GetTitle(); 105 case Item::TYPE_SEPARATOR: 106 // This function should not be called for separators. 107 NOTREACHED(); 108 return base::string16(); 109 case Item::TYPE_CHOOSE_ANOTHER_FOLDER: 110 return l10n_util::GetStringUTF16( 111 IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER); 112 } 113 NOTREACHED(); 114 return base::string16(); 115} 116 117bool RecentlyUsedFoldersComboModel::IsItemSeparatorAt(int index) { 118 return items_[index].type == Item::TYPE_SEPARATOR; 119} 120 121int RecentlyUsedFoldersComboModel::GetDefaultIndex() const { 122 return node_parent_index_; 123} 124 125void RecentlyUsedFoldersComboModel::AddObserver( 126 ui::ComboboxModelObserver* observer) { 127 observers_.AddObserver(observer); 128} 129 130void RecentlyUsedFoldersComboModel::RemoveObserver( 131 ui::ComboboxModelObserver* observer) { 132 observers_.RemoveObserver(observer); 133} 134 135void RecentlyUsedFoldersComboModel::BookmarkModelLoaded(BookmarkModel* model, 136 bool ids_reassigned) {} 137 138void RecentlyUsedFoldersComboModel::BookmarkModelBeingDeleted( 139 BookmarkModel* model) { 140} 141 142void RecentlyUsedFoldersComboModel::BookmarkNodeMoved( 143 BookmarkModel* model, 144 const BookmarkNode* old_parent, 145 int old_index, 146 const BookmarkNode* new_parent, 147 int new_index) { 148} 149 150void RecentlyUsedFoldersComboModel::BookmarkNodeAdded( 151 BookmarkModel* model, 152 const BookmarkNode* parent, 153 int index) { 154} 155 156void RecentlyUsedFoldersComboModel::OnWillRemoveBookmarks( 157 BookmarkModel* model, 158 const BookmarkNode* parent, 159 int old_index, 160 const BookmarkNode* node) { 161 // Changing is rare enough that we don't attempt to readjust the contents. 162 // Update |items_| so we aren't left pointing to a deleted node. 163 bool changed = false; 164 for (std::vector<Item>::iterator i = items_.begin(); 165 i != items_.end();) { 166 if (i->type == Item::TYPE_NODE && i->node->HasAncestor(node)) { 167 i = items_.erase(i); 168 changed = true; 169 } else { 170 ++i; 171 } 172 } 173 if (changed) { 174 FOR_EACH_OBSERVER(ui::ComboboxModelObserver, observers_, 175 OnComboboxModelChanged(this)); 176 } 177} 178 179void RecentlyUsedFoldersComboModel::BookmarkNodeRemoved( 180 BookmarkModel* model, 181 const BookmarkNode* parent, 182 int old_index, 183 const BookmarkNode* node) { 184} 185 186void RecentlyUsedFoldersComboModel::BookmarkNodeChanged( 187 BookmarkModel* model, 188 const BookmarkNode* node) { 189} 190 191void RecentlyUsedFoldersComboModel::BookmarkNodeFaviconChanged( 192 BookmarkModel* model, 193 const BookmarkNode* node) { 194} 195 196void RecentlyUsedFoldersComboModel::BookmarkNodeChildrenReordered( 197 BookmarkModel* model, 198 const BookmarkNode* node) { 199} 200 201void RecentlyUsedFoldersComboModel::BookmarkAllNodesRemoved( 202 BookmarkModel* model) { 203 // Changing is rare enough that we don't attempt to readjust the contents. 204 // Update |items_| so we aren't left pointing to a deleted node. 205 bool changed = false; 206 for (std::vector<Item>::iterator i = items_.begin(); 207 i != items_.end();) { 208 if (i->type == Item::TYPE_NODE && 209 !bookmark_model_->is_permanent_node(i->node)) { 210 i = items_.erase(i); 211 changed = true; 212 } else { 213 ++i; 214 } 215 } 216 if (changed) { 217 FOR_EACH_OBSERVER(ui::ComboboxModelObserver, observers_, 218 OnComboboxModelChanged(this)); 219 } 220} 221 222void RecentlyUsedFoldersComboModel::MaybeChangeParent( 223 const BookmarkNode* node, 224 int selected_index) { 225 if (items_[selected_index].type != Item::TYPE_NODE) 226 return; 227 228 const BookmarkNode* new_parent = GetNodeAt(selected_index); 229 if (new_parent != node->parent()) { 230 content::RecordAction( 231 base::UserMetricsAction("BookmarkBubble_ChangeParent")); 232 bookmark_model_->Move(node, new_parent, new_parent->child_count()); 233 } 234} 235 236const BookmarkNode* RecentlyUsedFoldersComboModel::GetNodeAt(int index) { 237 if (index < 0 || index >= static_cast<int>(items_.size())) 238 return NULL; 239 return items_[index].node; 240} 241 242void RecentlyUsedFoldersComboModel::RemoveNode(const BookmarkNode* node) { 243 std::vector<Item>::iterator it = std::find(items_.begin(), 244 items_.end(), 245 Item(node, Item::TYPE_NODE)); 246 if (it != items_.end()) 247 items_.erase(it); 248} 249