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 13 namespace { 14 15 // Max number of most recently used folders. 16 const size_t kMaxMRUFolders = 5; 17 18 } // namespace 19 20 struct RecentlyUsedFoldersComboModel::Item { 21 enum Type { 22 TYPE_NODE, 23 TYPE_SEPARATOR, 24 TYPE_CHOOSE_ANOTHER_FOLDER 25 }; 26 27 Item(const BookmarkNode* node, Type type); 28 ~Item(); 29 30 bool operator==(const Item& item) const; 31 32 const BookmarkNode* node; 33 Type type; 34 }; 35 36 RecentlyUsedFoldersComboModel::Item::Item(const BookmarkNode* node, 37 Type type) 38 : node(node), 39 type(type) { 40 } 41 42 RecentlyUsedFoldersComboModel::Item::~Item() {} 43 44 bool RecentlyUsedFoldersComboModel::Item::operator==(const Item& item) const { 45 return item.node == node && item.type == type; 46 } 47 48 RecentlyUsedFoldersComboModel::RecentlyUsedFoldersComboModel( 49 BookmarkModel* model, 50 const BookmarkNode* node) 51 : bookmark_model_(model), 52 node_parent_index_(0) { 53 // Use + 2 to account for bookmark bar and other node. 54 std::vector<const BookmarkNode*> nodes = 55 bookmark_utils::GetMostRecentlyModifiedFolders(model, kMaxMRUFolders + 2); 56 57 for (size_t i = 0; i < nodes.size(); ++i) 58 items_.push_back(Item(nodes[i], Item::TYPE_NODE)); 59 60 // We special case the placement of these, so remove them from the list, then 61 // fix up the order. 62 RemoveNode(model->bookmark_bar_node()); 63 RemoveNode(model->mobile_node()); 64 RemoveNode(model->other_node()); 65 RemoveNode(node->parent()); 66 67 // Make the parent the first item, unless it's a permanent node, which is 68 // added below. 69 if (!model->is_permanent_node(node->parent())) 70 items_.insert(items_.begin(), Item(node->parent(), Item::TYPE_NODE)); 71 72 // Make sure we only have kMaxMRUFolders in the first chunk. 73 if (items_.size() > kMaxMRUFolders) 74 items_.erase(items_.begin() + kMaxMRUFolders, items_.end()); 75 76 // And put the bookmark bar and other nodes at the end of the list. 77 items_.push_back(Item(model->bookmark_bar_node(), Item::TYPE_NODE)); 78 items_.push_back(Item(model->other_node(), Item::TYPE_NODE)); 79 if (model->mobile_node()->IsVisible()) 80 items_.push_back(Item(model->mobile_node(), Item::TYPE_NODE)); 81 #if defined(USE_AURA) || defined(TOOLKIT_GTK) 82 items_.push_back(Item(NULL, Item::TYPE_SEPARATOR)); 83 #endif 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 93 RecentlyUsedFoldersComboModel::~RecentlyUsedFoldersComboModel() {} 94 95 int RecentlyUsedFoldersComboModel::GetItemCount() const { 96 return static_cast<int>(items_.size()); 97 } 98 99 string16 RecentlyUsedFoldersComboModel::GetItemAt(int index) { 100 switch (items_[index].type) { 101 case Item::TYPE_NODE: 102 return items_[index].node->GetTitle(); 103 case Item::TYPE_SEPARATOR: 104 // This function should not be called for separators. 105 NOTREACHED(); 106 return string16(); 107 case Item::TYPE_CHOOSE_ANOTHER_FOLDER: 108 return l10n_util::GetStringUTF16( 109 IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER); 110 } 111 NOTREACHED(); 112 return string16(); 113 } 114 115 bool RecentlyUsedFoldersComboModel::IsItemSeparatorAt(int index) { 116 return items_[index].type == Item::TYPE_SEPARATOR; 117 } 118 119 int RecentlyUsedFoldersComboModel::GetDefaultIndex() const { 120 return node_parent_index_; 121 } 122 123 void RecentlyUsedFoldersComboModel::MaybeChangeParent( 124 const BookmarkNode* node, 125 int selected_index) { 126 if (items_[selected_index].type != Item::TYPE_NODE) 127 return; 128 129 const BookmarkNode* new_parent = GetNodeAt(selected_index); 130 if (new_parent != node->parent()) { 131 content::RecordAction( 132 content::UserMetricsAction("BookmarkBubble_ChangeParent")); 133 bookmark_model_->Move(node, new_parent, new_parent->child_count()); 134 } 135 } 136 137 const BookmarkNode* RecentlyUsedFoldersComboModel::GetNodeAt(int index) { 138 if (index < 0 || index >= static_cast<int>(items_.size())) 139 return NULL; 140 return items_[index].node; 141 } 142 143 void RecentlyUsedFoldersComboModel::RemoveNode(const BookmarkNode* node) { 144 std::vector<Item>::iterator it = std::find(items_.begin(), 145 items_.end(), 146 Item(node, Item::TYPE_NODE)); 147 if (it != items_.end()) 148 items_.erase(it); 149 } 150