Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / bookmarks / recently_used_folders_combo_model.cc
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 "components/bookmarks/browser/bookmark_model.h"
8 #include "components/bookmarks/browser/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
14 namespace {
15
16 // Max number of most recently used folders.
17 const size_t kMaxMRUFolders = 5;
18
19 }  // namespace
20
21 struct 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
37 RecentlyUsedFoldersComboModel::Item::Item(const BookmarkNode* node,
38                                           Type type)
39     : node(node),
40       type(type) {
41 }
42
43 RecentlyUsedFoldersComboModel::Item::~Item() {}
44
45 bool RecentlyUsedFoldersComboModel::Item::operator==(const Item& item) const {
46   return item.node == node && item.type == type;
47 }
48
49 RecentlyUsedFoldersComboModel::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       bookmarks::GetMostRecentlyModifiedUserFolders(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
93 RecentlyUsedFoldersComboModel::~RecentlyUsedFoldersComboModel() {
94   bookmark_model_->RemoveObserver(this);
95 }
96
97 int RecentlyUsedFoldersComboModel::GetItemCount() const {
98   return static_cast<int>(items_.size());
99 }
100
101 base::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
117 bool RecentlyUsedFoldersComboModel::IsItemSeparatorAt(int index) {
118   return items_[index].type == Item::TYPE_SEPARATOR;
119 }
120
121 int RecentlyUsedFoldersComboModel::GetDefaultIndex() const {
122   return node_parent_index_;
123 }
124
125 void RecentlyUsedFoldersComboModel::AddObserver(
126     ui::ComboboxModelObserver* observer) {
127   observers_.AddObserver(observer);
128 }
129
130 void RecentlyUsedFoldersComboModel::RemoveObserver(
131     ui::ComboboxModelObserver* observer) {
132   observers_.RemoveObserver(observer);
133 }
134
135 void RecentlyUsedFoldersComboModel::BookmarkModelLoaded(BookmarkModel* model,
136                                                         bool ids_reassigned) {}
137
138 void RecentlyUsedFoldersComboModel::BookmarkModelBeingDeleted(
139     BookmarkModel* model) {
140 }
141
142 void 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
150 void RecentlyUsedFoldersComboModel::BookmarkNodeAdded(
151     BookmarkModel* model,
152     const BookmarkNode* parent,
153     int index) {
154 }
155
156 void 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
179 void RecentlyUsedFoldersComboModel::BookmarkNodeRemoved(
180     BookmarkModel* model,
181     const BookmarkNode* parent,
182     int old_index,
183     const BookmarkNode* node,
184     const std::set<GURL>& removed_urls) {}
185
186 void RecentlyUsedFoldersComboModel::BookmarkNodeChanged(
187     BookmarkModel* model,
188     const BookmarkNode* node) {
189 }
190
191 void RecentlyUsedFoldersComboModel::BookmarkNodeFaviconChanged(
192     BookmarkModel* model,
193     const BookmarkNode* node) {
194 }
195
196 void RecentlyUsedFoldersComboModel::BookmarkNodeChildrenReordered(
197       BookmarkModel* model,
198       const BookmarkNode* node) {
199 }
200
201 void RecentlyUsedFoldersComboModel::BookmarkAllUserNodesRemoved(
202     BookmarkModel* model,
203     const std::set<GURL>& removed_urls) {
204   // Changing is rare enough that we don't attempt to readjust the contents.
205   // Update |items_| so we aren't left pointing to a deleted node.
206   bool changed = false;
207   for (std::vector<Item>::iterator i = items_.begin();
208        i != items_.end();) {
209     if (i->type == Item::TYPE_NODE &&
210         !bookmark_model_->is_permanent_node(i->node)) {
211       i = items_.erase(i);
212       changed = true;
213     } else {
214       ++i;
215     }
216   }
217   if (changed) {
218     FOR_EACH_OBSERVER(ui::ComboboxModelObserver, observers_,
219                       OnComboboxModelChanged(this));
220   }
221 }
222
223 void RecentlyUsedFoldersComboModel::MaybeChangeParent(
224     const BookmarkNode* node,
225     int selected_index) {
226   if (items_[selected_index].type != Item::TYPE_NODE)
227     return;
228
229   const BookmarkNode* new_parent = GetNodeAt(selected_index);
230   if (new_parent != node->parent()) {
231     content::RecordAction(
232         base::UserMetricsAction("BookmarkBubble_ChangeParent"));
233     bookmark_model_->Move(node, new_parent, new_parent->child_count());
234   }
235 }
236
237 const BookmarkNode* RecentlyUsedFoldersComboModel::GetNodeAt(int index) {
238   if (index < 0 || index >= static_cast<int>(items_.size()))
239     return NULL;
240   return items_[index].node;
241 }
242
243 void RecentlyUsedFoldersComboModel::RemoveNode(const BookmarkNode* node) {
244   std::vector<Item>::iterator it = std::find(items_.begin(),
245                                              items_.end(),
246                                              Item(node, Item::TYPE_NODE));
247   if (it != items_.end())
248     items_.erase(it);
249 }