BookmarkManager: Fix 'new folder text field size changes on clicking it' issue.
[chromium-blink-merge.git] / chrome / browser / ui / bookmarks / recently_used_folders_combo_model.cc
blob8df3292df1651fd7873a7bf24ba8b5ad89e765c0
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.
5 #include "chrome/browser/ui/bookmarks/recently_used_folders_combo_model.h"
7 #include "chrome/grit/generated_resources.h"
8 #include "components/bookmarks/browser/bookmark_model.h"
9 #include "components/bookmarks/browser/bookmark_utils.h"
10 #include "content/public/browser/user_metrics.h"
11 #include "ui/base/l10n/l10n_util.h"
12 #include "ui/base/models/combobox_model_observer.h"
14 using bookmarks::BookmarkModel;
15 using bookmarks::BookmarkNode;
17 namespace {
19 // Max number of most recently used folders.
20 const size_t kMaxMRUFolders = 5;
22 } // namespace
24 struct RecentlyUsedFoldersComboModel::Item {
25 enum Type {
26 TYPE_NODE,
27 TYPE_SEPARATOR,
28 TYPE_CHOOSE_ANOTHER_FOLDER
31 Item(const BookmarkNode* node, Type type);
32 ~Item();
34 bool operator==(const Item& item) const;
36 const BookmarkNode* node;
37 Type type;
40 RecentlyUsedFoldersComboModel::Item::Item(const BookmarkNode* node,
41 Type type)
42 : node(node),
43 type(type) {
46 RecentlyUsedFoldersComboModel::Item::~Item() {}
48 bool RecentlyUsedFoldersComboModel::Item::operator==(const Item& item) const {
49 return item.node == node && item.type == type;
52 RecentlyUsedFoldersComboModel::RecentlyUsedFoldersComboModel(
53 BookmarkModel* model,
54 const BookmarkNode* node)
55 : bookmark_model_(model),
56 node_parent_index_(0) {
57 bookmark_model_->AddObserver(this);
58 // Use + 2 to account for bookmark bar and other node.
59 std::vector<const BookmarkNode*> nodes =
60 bookmarks::GetMostRecentlyModifiedUserFolders(model, kMaxMRUFolders + 2);
62 for (size_t i = 0; i < nodes.size(); ++i)
63 items_.push_back(Item(nodes[i], Item::TYPE_NODE));
65 // We special case the placement of these, so remove them from the list, then
66 // fix up the order.
67 RemoveNode(model->bookmark_bar_node());
68 RemoveNode(model->mobile_node());
69 RemoveNode(model->other_node());
70 RemoveNode(node->parent());
72 // Make the parent the first item, unless it's a permanent node, which is
73 // added below.
74 if (!model->is_permanent_node(node->parent()))
75 items_.insert(items_.begin(), Item(node->parent(), Item::TYPE_NODE));
77 // Make sure we only have kMaxMRUFolders in the first chunk.
78 if (items_.size() > kMaxMRUFolders)
79 items_.erase(items_.begin() + kMaxMRUFolders, items_.end());
81 // And put the bookmark bar and other nodes at the end of the list.
82 items_.push_back(Item(model->bookmark_bar_node(), Item::TYPE_NODE));
83 items_.push_back(Item(model->other_node(), Item::TYPE_NODE));
84 if (model->mobile_node()->IsVisible())
85 items_.push_back(Item(model->mobile_node(), Item::TYPE_NODE));
86 items_.push_back(Item(NULL, Item::TYPE_SEPARATOR));
87 items_.push_back(Item(NULL, Item::TYPE_CHOOSE_ANOTHER_FOLDER));
89 std::vector<Item>::iterator it = std::find(items_.begin(),
90 items_.end(),
91 Item(node->parent(),
92 Item::TYPE_NODE));
93 node_parent_index_ = static_cast<int>(it - items_.begin());
96 RecentlyUsedFoldersComboModel::~RecentlyUsedFoldersComboModel() {
97 bookmark_model_->RemoveObserver(this);
100 int RecentlyUsedFoldersComboModel::GetItemCount() const {
101 return static_cast<int>(items_.size());
104 base::string16 RecentlyUsedFoldersComboModel::GetItemAt(int index) {
105 switch (items_[index].type) {
106 case Item::TYPE_NODE:
107 return items_[index].node->GetTitle();
108 case Item::TYPE_SEPARATOR:
109 // This function should not be called for separators.
110 NOTREACHED();
111 return base::string16();
112 case Item::TYPE_CHOOSE_ANOTHER_FOLDER:
113 return l10n_util::GetStringUTF16(
114 IDS_BOOKMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER);
116 NOTREACHED();
117 return base::string16();
120 bool RecentlyUsedFoldersComboModel::IsItemSeparatorAt(int index) {
121 return items_[index].type == Item::TYPE_SEPARATOR;
124 int RecentlyUsedFoldersComboModel::GetDefaultIndex() const {
125 return node_parent_index_;
128 void RecentlyUsedFoldersComboModel::AddObserver(
129 ui::ComboboxModelObserver* observer) {
130 observers_.AddObserver(observer);
133 void RecentlyUsedFoldersComboModel::RemoveObserver(
134 ui::ComboboxModelObserver* observer) {
135 observers_.RemoveObserver(observer);
138 void RecentlyUsedFoldersComboModel::BookmarkModelLoaded(BookmarkModel* model,
139 bool ids_reassigned) {}
141 void RecentlyUsedFoldersComboModel::BookmarkModelBeingDeleted(
142 BookmarkModel* model) {
145 void RecentlyUsedFoldersComboModel::BookmarkNodeMoved(
146 BookmarkModel* model,
147 const BookmarkNode* old_parent,
148 int old_index,
149 const BookmarkNode* new_parent,
150 int new_index) {
153 void RecentlyUsedFoldersComboModel::BookmarkNodeAdded(
154 BookmarkModel* model,
155 const BookmarkNode* parent,
156 int index) {
159 void RecentlyUsedFoldersComboModel::OnWillRemoveBookmarks(
160 BookmarkModel* model,
161 const BookmarkNode* parent,
162 int old_index,
163 const BookmarkNode* node) {
164 // Changing is rare enough that we don't attempt to readjust the contents.
165 // Update |items_| so we aren't left pointing to a deleted node.
166 bool changed = false;
167 for (std::vector<Item>::iterator i = items_.begin();
168 i != items_.end();) {
169 if (i->type == Item::TYPE_NODE && i->node->HasAncestor(node)) {
170 i = items_.erase(i);
171 changed = true;
172 } else {
173 ++i;
176 if (changed) {
177 FOR_EACH_OBSERVER(ui::ComboboxModelObserver, observers_,
178 OnComboboxModelChanged(this));
182 void RecentlyUsedFoldersComboModel::BookmarkNodeRemoved(
183 BookmarkModel* model,
184 const BookmarkNode* parent,
185 int old_index,
186 const BookmarkNode* node,
187 const std::set<GURL>& removed_urls) {}
189 void RecentlyUsedFoldersComboModel::BookmarkNodeChanged(
190 BookmarkModel* model,
191 const BookmarkNode* node) {
194 void RecentlyUsedFoldersComboModel::BookmarkNodeFaviconChanged(
195 BookmarkModel* model,
196 const BookmarkNode* node) {
199 void RecentlyUsedFoldersComboModel::BookmarkNodeChildrenReordered(
200 BookmarkModel* model,
201 const BookmarkNode* node) {
204 void RecentlyUsedFoldersComboModel::BookmarkAllUserNodesRemoved(
205 BookmarkModel* model,
206 const std::set<GURL>& removed_urls) {
207 // Changing is rare enough that we don't attempt to readjust the contents.
208 // Update |items_| so we aren't left pointing to a deleted node.
209 bool changed = false;
210 for (std::vector<Item>::iterator i = items_.begin();
211 i != items_.end();) {
212 if (i->type == Item::TYPE_NODE &&
213 !bookmark_model_->is_permanent_node(i->node)) {
214 i = items_.erase(i);
215 changed = true;
216 } else {
217 ++i;
220 if (changed) {
221 FOR_EACH_OBSERVER(ui::ComboboxModelObserver, observers_,
222 OnComboboxModelChanged(this));
226 void RecentlyUsedFoldersComboModel::MaybeChangeParent(
227 const BookmarkNode* node,
228 int selected_index) {
229 if (items_[selected_index].type != Item::TYPE_NODE)
230 return;
232 const BookmarkNode* new_parent = GetNodeAt(selected_index);
233 if (new_parent != node->parent()) {
234 content::RecordAction(
235 base::UserMetricsAction("BookmarkBubble_ChangeParent"));
236 bookmark_model_->Move(node, new_parent, new_parent->child_count());
240 const BookmarkNode* RecentlyUsedFoldersComboModel::GetNodeAt(int index) {
241 if (index < 0 || index >= static_cast<int>(items_.size()))
242 return NULL;
243 return items_[index].node;
246 void RecentlyUsedFoldersComboModel::RemoveNode(const BookmarkNode* node) {
247 std::vector<Item>::iterator it = std::find(items_.begin(),
248 items_.end(),
249 Item(node, Item::TYPE_NODE));
250 if (it != items_.end())
251 items_.erase(it);