Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / app_list / app_list_item_list.cc
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.
4
5 #include "ui/app_list/app_list_item_list.h"
6
7 #include "ui/app_list/app_list_item.h"
8
9 namespace app_list {
10
11 AppListItemList::AppListItemList() {
12 }
13
14 AppListItemList::~AppListItemList() {
15 }
16
17 void AppListItemList::AddObserver(AppListItemListObserver* observer) {
18   observers_.AddObserver(observer);
19 }
20
21 void AppListItemList::RemoveObserver(AppListItemListObserver* observer) {
22   DCHECK(observers_.HasObserver(observer));
23   observers_.RemoveObserver(observer);
24 }
25
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;
31   }
32   return NULL;
33 }
34
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;
41     }
42   }
43   return false;
44 }
45
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;
51
52   AppListItem* target_item = app_list_items_[from_index];
53   DVLOG(2) << "MoveItem: " << from_index << " -> " << to_index << " ["
54            << target_item->position().ToDebugString() << "]";
55
56   // Remove the target item
57   app_list_items_.weak_erase(app_list_items_.begin() + from_index);
58
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());
76   }
77   target_item->set_position(new_position);
78
79   DVLOG(2) << "Move: "
80            << " Prev: " << (prev ? prev->position().ToDebugString() : "(none)")
81            << " Next: " << (next ? next->position().ToDebugString() : "(none)")
82            << " -> " << new_position.ToDebugString();
83
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));
89 }
90
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;
98   }
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();
105   }
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;
113   }
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));
125 }
126
127 void AppListItemList::HighlightItemInstalledFromUI(const std::string& id) {
128   // Items within folders are not highlighted (apps are never installed to a
129   // folder initially). So just search the top-level list.
130   size_t index;
131   if (FindItemIndex(highlighted_id_, &index)) {
132     item_at(index)->set_highlighted(false);
133     FOR_EACH_OBSERVER(AppListItemListObserver,
134                       observers_,
135                       OnAppListItemHighlight(index, false));
136   }
137   highlighted_id_ = id;
138   if (!FindItemIndex(highlighted_id_, &index)) {
139     // If the item isin't in the app list yet, it will be highlighted later, in
140     // AddItem().
141     return;
142   }
143
144   item_at(index)->set_highlighted(true);
145   FOR_EACH_OBSERVER(
146       AppListItemListObserver, observers_, OnAppListItemHighlight(index, true));
147 }
148
149 // AppListItemList private
150
151 syncer::StringOrdinal AppListItemList::CreatePositionBefore(
152     const syncer::StringOrdinal& position) {
153   if (app_list_items_.empty())
154     return syncer::StringOrdinal::CreateInitialOrdinal();
155
156   size_t nitems = app_list_items_.size();
157   size_t index;
158   if (!position.IsValid()) {
159     index = nitems;
160   } else {
161     for (index = 0; index < nitems; ++index) {
162       if (!app_list_items_[index]->position().LessThan(position))
163         break;
164     }
165   }
166   if (index == 0)
167     return app_list_items_[0]->position().CreateBefore();
168   if (index == nitems)
169     return app_list_items_[nitems - 1]->position().CreateAfter();
170   return app_list_items_[index - 1]->position().CreateBetween(
171       app_list_items_[index]->position());
172 }
173
174 AppListItem* AppListItemList::AddItem(scoped_ptr<AppListItem> item_ptr) {
175   AppListItem* item = item_ptr.get();
176   CHECK(std::find(app_list_items_.begin(), app_list_items_.end(), item)
177         == app_list_items_.end());
178   EnsureValidItemPosition(item);
179   size_t index = GetItemSortOrderIndex(item->position(), item->id());
180   app_list_items_.insert(app_list_items_.begin() + index, item_ptr.release());
181   FOR_EACH_OBSERVER(AppListItemListObserver,
182                     observers_,
183                     OnListItemAdded(index, item));
184
185   if (item->id() == highlighted_id_) {
186     // Item not present when highlight requested, so highlight it now.
187     item->set_highlighted(true);
188     FOR_EACH_OBSERVER(AppListItemListObserver,
189                       observers_,
190                       OnAppListItemHighlight(index, true));
191   }
192   return item;
193 }
194
195 void AppListItemList::DeleteItem(const std::string& id) {
196   scoped_ptr<AppListItem> item = RemoveItem(id);
197   // |item| will be deleted on destruction.
198 }
199
200 scoped_ptr<AppListItem> AppListItemList::RemoveItem(const std::string& id) {
201   size_t index;
202   if (!FindItemIndex(id, &index))
203     LOG(FATAL) << "RemoveItem: Not found: " << id;
204   return RemoveItemAt(index);
205 }
206
207 scoped_ptr<AppListItem> AppListItemList::RemoveItemAt(size_t index) {
208   CHECK_LT(index, item_count());
209   AppListItem* item = app_list_items_[index];
210   app_list_items_.weak_erase(app_list_items_.begin() + index);
211   FOR_EACH_OBSERVER(AppListItemListObserver,
212                     observers_,
213                     OnListItemRemoved(index, item));
214   return make_scoped_ptr<AppListItem>(item);
215 }
216
217 void AppListItemList::DeleteItemAt(size_t index) {
218   scoped_ptr<AppListItem> item = RemoveItemAt(index);
219   // |item| will be deleted on destruction.
220 }
221
222 void AppListItemList::EnsureValidItemPosition(AppListItem* item) {
223   syncer::StringOrdinal position = item->position();
224   if (position.IsValid())
225     return;
226   size_t nitems = app_list_items_.size();
227   if (nitems == 0) {
228     position = syncer::StringOrdinal::CreateInitialOrdinal();
229   } else {
230     position = app_list_items_[nitems - 1]->position().CreateAfter();
231   }
232   item->set_position(position);
233 }
234
235 size_t AppListItemList::GetItemSortOrderIndex(
236     const syncer::StringOrdinal& position,
237     const std::string& id) {
238   DCHECK(position.IsValid());
239   for (size_t index = 0; index < app_list_items_.size(); ++index) {
240     if (position.LessThan(app_list_items_[index]->position()) ||
241         (position.Equals(app_list_items_[index]->position()) &&
242          (id < app_list_items_[index]->id()))) {
243       return index;
244     }
245   }
246   return app_list_items_.size();
247 }
248
249 void AppListItemList::FixItemPosition(size_t index) {
250   DVLOG(1) << "FixItemPosition: " << index;
251   size_t nitems = item_count();
252   DCHECK_LT(index, nitems);
253   DCHECK_GT(index, 0u);
254   // Update the position of |index| and any necessary subsequent items.
255   // First, find the next item that has a different position.
256   AppListItem* prev = app_list_items_[index - 1];
257   size_t last_index = index + 1;
258   for (; last_index < nitems; ++last_index) {
259     if (!app_list_items_[last_index]->position().Equals(prev->position()))
260       break;
261   }
262   AppListItem* last = last_index < nitems ? app_list_items_[last_index] : NULL;
263   for (size_t i = index; i < last_index; ++i) {
264     AppListItem* cur = app_list_items_[i];
265     if (last)
266       cur->set_position(prev->position().CreateBetween(last->position()));
267     else
268       cur->set_position(prev->position().CreateAfter());
269     prev = cur;
270   }
271   FOR_EACH_OBSERVER(AppListItemListObserver,
272                     observers_,
273                     OnListItemMoved(index, index, app_list_items_[index]));
274 }
275
276 }  // namespace app_list