Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / app_list / app_list_item_list.cc
blobc8d96e2aec1a7c35ffd54ebf6079fbdd45f21b98
1 // Copyright (c) 2013 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 "ui/app_list/app_list_item_list.h"
7 #include "ui/app_list/app_list_item.h"
9 namespace app_list {
11 AppListItemList::AppListItemList() {
14 AppListItemList::~AppListItemList() {
17 void AppListItemList::AddObserver(AppListItemListObserver* observer) {
18 observers_.AddObserver(observer);
21 void AppListItemList::RemoveObserver(AppListItemListObserver* observer) {
22 observers_.RemoveObserver(observer);
25 AppListItem* AppListItemList::FindItem(const std::string& id) {
26 for (size_t i = 0; i < app_list_items_.size(); ++i) {
27 AppListItem* item = app_list_items_[i];
28 if (item->id() == id)
29 return item;
31 return NULL;
34 bool AppListItemList::FindItemIndex(const std::string& id, size_t* index) {
35 for (size_t i = 0; i < app_list_items_.size(); ++i) {
36 AppListItem* item = app_list_items_[i];
37 if (item->id() == id) {
38 *index = i;
39 return true;
42 return false;
45 void AppListItemList::MoveItem(size_t from_index, size_t to_index) {
46 DCHECK_LT(from_index, item_count());
47 DCHECK_LT(to_index, item_count());
48 if (from_index == to_index)
49 return;
51 AppListItem* target_item = app_list_items_[from_index];
52 DVLOG(2) << "MoveItem: " << from_index << " -> " << to_index << " ["
53 << target_item->position().ToDebugString() << "]";
55 // Remove the target item
56 app_list_items_.weak_erase(app_list_items_.begin() + from_index);
58 // Update the position
59 AppListItem* prev = to_index > 0 ? app_list_items_[to_index - 1] : NULL;
60 AppListItem* next =
61 to_index < item_count() ? app_list_items_[to_index] : NULL;
62 CHECK_NE(prev, next);
63 syncer::StringOrdinal new_position;
64 if (!prev) {
65 new_position = next->position().CreateBefore();
66 } else if (!next) {
67 new_position = prev->position().CreateAfter();
68 } else {
69 // It is possible that items were added with the same ordinal. To
70 // successfully move the item we need to fix this. We do not try to fix this
71 // when an item is added in order to avoid possible edge cases with sync.
72 if (prev->position().Equals(next->position()))
73 FixItemPosition(to_index);
74 new_position = prev->position().CreateBetween(next->position());
76 target_item->set_position(new_position);
78 DVLOG(2) << "Move: "
79 << " Prev: " << (prev ? prev->position().ToDebugString() : "(none)")
80 << " Next: " << (next ? next->position().ToDebugString() : "(none)")
81 << " -> " << new_position.ToDebugString();
83 // Insert the item and notify observers.
84 app_list_items_.insert(app_list_items_.begin() + to_index, target_item);
85 FOR_EACH_OBSERVER(AppListItemListObserver,
86 observers_,
87 OnListItemMoved(from_index, to_index, target_item));
90 void AppListItemList::SetItemPosition(AppListItem* item,
91 syncer::StringOrdinal new_position) {
92 DCHECK(item);
93 size_t from_index;
94 if (!FindItemIndex(item->id(), &from_index)) {
95 LOG(ERROR) << "SetItemPosition: Not in list: " << item->id().substr(0, 8);
96 return;
98 DCHECK(app_list_items_[from_index] == item);
99 if (!new_position.IsValid()) {
100 size_t last_index = app_list_items_.size() - 1;
101 if (from_index == last_index)
102 return; // Already last item, do nothing.
103 new_position = app_list_items_[last_index]->position().CreateAfter();
105 // First check if the order would remain the same, in which case just update
106 // the position.
107 size_t to_index = GetItemSortOrderIndex(new_position, item->id());
108 if (to_index == from_index) {
109 DVLOG(2) << "SetItemPosition: No change: " << item->id().substr(0, 8);
110 item->set_position(new_position);
111 return;
113 // Remove the item and get the updated to index.
114 app_list_items_.weak_erase(app_list_items_.begin() + from_index);
115 to_index = GetItemSortOrderIndex(new_position, item->id());
116 DVLOG(2) << "SetItemPosition: " << item->id().substr(0, 8) << " -> "
117 << new_position.ToDebugString() << " From: " << from_index
118 << " To: " << to_index;
119 item->set_position(new_position);
120 app_list_items_.insert(app_list_items_.begin() + to_index, item);
121 FOR_EACH_OBSERVER(AppListItemListObserver,
122 observers_,
123 OnListItemMoved(from_index, to_index, item));
126 // AppListItemList private
128 syncer::StringOrdinal AppListItemList::CreatePositionBefore(
129 const syncer::StringOrdinal& position) {
130 if (app_list_items_.empty())
131 return syncer::StringOrdinal::CreateInitialOrdinal();
133 size_t nitems = app_list_items_.size();
134 size_t index;
135 if (!position.IsValid()) {
136 index = nitems;
137 } else {
138 for (index = 0; index < nitems; ++index) {
139 if (!app_list_items_[index]->position().LessThan(position))
140 break;
143 if (index == 0)
144 return app_list_items_[0]->position().CreateBefore();
145 if (index == nitems)
146 return app_list_items_[nitems - 1]->position().CreateAfter();
147 return app_list_items_[index - 1]->position().CreateBetween(
148 app_list_items_[index]->position());
151 AppListItem* AppListItemList::AddItem(scoped_ptr<AppListItem> item_ptr) {
152 AppListItem* item = item_ptr.get();
153 CHECK(std::find(app_list_items_.begin(), app_list_items_.end(), item)
154 == app_list_items_.end());
155 EnsureValidItemPosition(item);
156 size_t index = GetItemSortOrderIndex(item->position(), item->id());
157 app_list_items_.insert(app_list_items_.begin() + index, item_ptr.release());
158 FOR_EACH_OBSERVER(AppListItemListObserver,
159 observers_,
160 OnListItemAdded(index, item));
161 return item;
164 void AppListItemList::DeleteItem(const std::string& id) {
165 scoped_ptr<AppListItem> item = RemoveItem(id);
166 // |item| will be deleted on destruction.
169 scoped_ptr<AppListItem> AppListItemList::RemoveItem(const std::string& id) {
170 size_t index;
171 if (!FindItemIndex(id, &index))
172 LOG(FATAL) << "RemoveItem: Not found: " << id;
173 return RemoveItemAt(index);
176 scoped_ptr<AppListItem> AppListItemList::RemoveItemAt(size_t index) {
177 CHECK_LT(index, item_count());
178 AppListItem* item = app_list_items_[index];
179 app_list_items_.weak_erase(app_list_items_.begin() + index);
180 FOR_EACH_OBSERVER(AppListItemListObserver,
181 observers_,
182 OnListItemRemoved(index, item));
183 return make_scoped_ptr<AppListItem>(item);
186 void AppListItemList::DeleteItemAt(size_t index) {
187 scoped_ptr<AppListItem> item = RemoveItemAt(index);
188 // |item| will be deleted on destruction.
191 void AppListItemList::EnsureValidItemPosition(AppListItem* item) {
192 syncer::StringOrdinal position = item->position();
193 if (position.IsValid())
194 return;
195 size_t nitems = app_list_items_.size();
196 if (nitems == 0) {
197 position = syncer::StringOrdinal::CreateInitialOrdinal();
198 } else {
199 position = app_list_items_[nitems - 1]->position().CreateAfter();
201 item->set_position(position);
204 size_t AppListItemList::GetItemSortOrderIndex(
205 const syncer::StringOrdinal& position,
206 const std::string& id) {
207 DCHECK(position.IsValid());
208 for (size_t index = 0; index < app_list_items_.size(); ++index) {
209 if (position.LessThan(app_list_items_[index]->position()) ||
210 (position.Equals(app_list_items_[index]->position()) &&
211 (id < app_list_items_[index]->id()))) {
212 return index;
215 return app_list_items_.size();
218 void AppListItemList::FixItemPosition(size_t index) {
219 DVLOG(1) << "FixItemPosition: " << index;
220 size_t nitems = item_count();
221 DCHECK_LT(index, nitems);
222 DCHECK_GT(index, 0u);
223 // Update the position of |index| and any necessary subsequent items.
224 // First, find the next item that has a different position.
225 AppListItem* prev = app_list_items_[index - 1];
226 size_t last_index = index + 1;
227 for (; last_index < nitems; ++last_index) {
228 if (!app_list_items_[last_index]->position().Equals(prev->position()))
229 break;
231 AppListItem* last = last_index < nitems ? app_list_items_[last_index] : NULL;
232 for (size_t i = index; i < last_index; ++i) {
233 AppListItem* cur = app_list_items_[i];
234 if (last)
235 cur->set_position(prev->position().CreateBetween(last->position()));
236 else
237 cur->set_position(prev->position().CreateAfter());
238 prev = cur;
240 FOR_EACH_OBSERVER(AppListItemListObserver,
241 observers_,
242 OnListItemMoved(index, index, app_list_items_[index]));
245 } // namespace app_list