Fix android webview test shell command line file path for Telemetry
[chromium-blink-merge.git] / ui / app_list / app_list_item_list.cc
blobe7c935081d1322b6f6391c5f4bf8ea069c68505b
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 DCHECK(observers_.HasObserver(observer));
23 observers_.RemoveObserver(observer);
26 AppListItem* AppListItemList::FindItem(const std::string& id) {
27 for (size_t i = 0; i < app_list_items_.size(); ++i) {
28 AppListItem* item = app_list_items_[i];
29 if (item->id() == id)
30 return item;
32 return NULL;
35 bool AppListItemList::FindItemIndex(const std::string& id, size_t* index) {
36 for (size_t i = 0; i < app_list_items_.size(); ++i) {
37 AppListItem* item = app_list_items_[i];
38 if (item->id() == id) {
39 *index = i;
40 return true;
43 return false;
46 void AppListItemList::MoveItem(size_t from_index, size_t to_index) {
47 DCHECK_LT(from_index, item_count());
48 DCHECK_LT(to_index, item_count());
49 if (from_index == to_index)
50 return;
52 AppListItem* target_item = app_list_items_[from_index];
53 DVLOG(2) << "MoveItem: " << from_index << " -> " << to_index << " ["
54 << target_item->position().ToDebugString() << "]";
56 // Remove the target item
57 app_list_items_.weak_erase(app_list_items_.begin() + from_index);
59 // Update the position
60 AppListItem* prev = to_index > 0 ? app_list_items_[to_index - 1] : NULL;
61 AppListItem* next =
62 to_index < item_count() ? app_list_items_[to_index] : NULL;
63 CHECK_NE(prev, next);
64 syncer::StringOrdinal new_position;
65 if (!prev) {
66 new_position = next->position().CreateBefore();
67 } else if (!next) {
68 new_position = prev->position().CreateAfter();
69 } else {
70 // It is possible that items were added with the same ordinal. To
71 // successfully move the item we need to fix this. We do not try to fix this
72 // when an item is added in order to avoid possible edge cases with sync.
73 if (prev->position().Equals(next->position()))
74 FixItemPosition(to_index);
75 new_position = prev->position().CreateBetween(next->position());
77 target_item->set_position(new_position);
79 DVLOG(2) << "Move: "
80 << " Prev: " << (prev ? prev->position().ToDebugString() : "(none)")
81 << " Next: " << (next ? next->position().ToDebugString() : "(none)")
82 << " -> " << new_position.ToDebugString();
84 // Insert the item and notify observers.
85 app_list_items_.insert(app_list_items_.begin() + to_index, target_item);
86 FOR_EACH_OBSERVER(AppListItemListObserver,
87 observers_,
88 OnListItemMoved(from_index, to_index, target_item));
91 void AppListItemList::SetItemPosition(AppListItem* item,
92 syncer::StringOrdinal new_position) {
93 DCHECK(item);
94 size_t from_index;
95 if (!FindItemIndex(item->id(), &from_index)) {
96 LOG(ERROR) << "SetItemPosition: Not in list: " << item->id().substr(0, 8);
97 return;
99 DCHECK(app_list_items_[from_index] == item);
100 if (!new_position.IsValid()) {
101 size_t last_index = app_list_items_.size() - 1;
102 if (from_index == last_index)
103 return; // Already last item, do nothing.
104 new_position = app_list_items_[last_index]->position().CreateAfter();
106 // First check if the order would remain the same, in which case just update
107 // the position.
108 size_t to_index = GetItemSortOrderIndex(new_position, item->id());
109 if (to_index == from_index) {
110 DVLOG(2) << "SetItemPosition: No change: " << item->id().substr(0, 8);
111 item->set_position(new_position);
112 return;
114 // Remove the item and get the updated to index.
115 app_list_items_.weak_erase(app_list_items_.begin() + from_index);
116 to_index = GetItemSortOrderIndex(new_position, item->id());
117 DVLOG(2) << "SetItemPosition: " << item->id().substr(0, 8) << " -> "
118 << new_position.ToDebugString() << " From: " << from_index
119 << " To: " << to_index;
120 item->set_position(new_position);
121 app_list_items_.insert(app_list_items_.begin() + to_index, item);
122 FOR_EACH_OBSERVER(AppListItemListObserver,
123 observers_,
124 OnListItemMoved(from_index, to_index, item));
127 // AppListItemList private
129 syncer::StringOrdinal AppListItemList::CreatePositionBefore(
130 const syncer::StringOrdinal& position) {
131 if (app_list_items_.empty())
132 return syncer::StringOrdinal::CreateInitialOrdinal();
134 size_t nitems = app_list_items_.size();
135 size_t index;
136 if (!position.IsValid()) {
137 index = nitems;
138 } else {
139 for (index = 0; index < nitems; ++index) {
140 if (!app_list_items_[index]->position().LessThan(position))
141 break;
144 if (index == 0)
145 return app_list_items_[0]->position().CreateBefore();
146 if (index == nitems)
147 return app_list_items_[nitems - 1]->position().CreateAfter();
148 return app_list_items_[index - 1]->position().CreateBetween(
149 app_list_items_[index]->position());
152 AppListItem* AppListItemList::AddItem(scoped_ptr<AppListItem> item_ptr) {
153 AppListItem* item = item_ptr.get();
154 CHECK(std::find(app_list_items_.begin(), app_list_items_.end(), item)
155 == app_list_items_.end());
156 EnsureValidItemPosition(item);
157 size_t index = GetItemSortOrderIndex(item->position(), item->id());
158 app_list_items_.insert(app_list_items_.begin() + index, item_ptr.release());
159 FOR_EACH_OBSERVER(AppListItemListObserver,
160 observers_,
161 OnListItemAdded(index, item));
162 return item;
165 void AppListItemList::DeleteItem(const std::string& id) {
166 scoped_ptr<AppListItem> item = RemoveItem(id);
167 // |item| will be deleted on destruction.
170 scoped_ptr<AppListItem> AppListItemList::RemoveItem(const std::string& id) {
171 size_t index;
172 if (!FindItemIndex(id, &index))
173 LOG(FATAL) << "RemoveItem: Not found: " << id;
174 return RemoveItemAt(index);
177 scoped_ptr<AppListItem> AppListItemList::RemoveItemAt(size_t index) {
178 CHECK_LT(index, item_count());
179 AppListItem* item = app_list_items_[index];
180 app_list_items_.weak_erase(app_list_items_.begin() + index);
181 FOR_EACH_OBSERVER(AppListItemListObserver,
182 observers_,
183 OnListItemRemoved(index, item));
184 return make_scoped_ptr<AppListItem>(item);
187 void AppListItemList::DeleteItemAt(size_t index) {
188 scoped_ptr<AppListItem> item = RemoveItemAt(index);
189 // |item| will be deleted on destruction.
192 void AppListItemList::EnsureValidItemPosition(AppListItem* item) {
193 syncer::StringOrdinal position = item->position();
194 if (position.IsValid())
195 return;
196 size_t nitems = app_list_items_.size();
197 if (nitems == 0) {
198 position = syncer::StringOrdinal::CreateInitialOrdinal();
199 } else {
200 position = app_list_items_[nitems - 1]->position().CreateAfter();
202 item->set_position(position);
205 size_t AppListItemList::GetItemSortOrderIndex(
206 const syncer::StringOrdinal& position,
207 const std::string& id) {
208 DCHECK(position.IsValid());
209 for (size_t index = 0; index < app_list_items_.size(); ++index) {
210 if (position.LessThan(app_list_items_[index]->position()) ||
211 (position.Equals(app_list_items_[index]->position()) &&
212 (id < app_list_items_[index]->id()))) {
213 return index;
216 return app_list_items_.size();
219 void AppListItemList::FixItemPosition(size_t index) {
220 DVLOG(1) << "FixItemPosition: " << index;
221 size_t nitems = item_count();
222 DCHECK_LT(index, nitems);
223 DCHECK_GT(index, 0u);
224 // Update the position of |index| and any necessary subsequent items.
225 // First, find the next item that has a different position.
226 AppListItem* prev = app_list_items_[index - 1];
227 size_t last_index = index + 1;
228 for (; last_index < nitems; ++last_index) {
229 if (!app_list_items_[last_index]->position().Equals(prev->position()))
230 break;
232 AppListItem* last = last_index < nitems ? app_list_items_[last_index] : NULL;
233 for (size_t i = index; i < last_index; ++i) {
234 AppListItem* cur = app_list_items_[i];
235 if (last)
236 cur->set_position(prev->position().CreateBetween(last->position()));
237 else
238 cur->set_position(prev->position().CreateAfter());
239 prev = cur;
241 FOR_EACH_OBSERVER(AppListItemListObserver,
242 observers_,
243 OnListItemMoved(index, index, app_list_items_[index]));
246 } // namespace app_list