Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ui / app_list / app_list_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 "ui/app_list/app_list_model.h"
6
7 #include "ui/app_list/app_list_folder_item.h"
8 #include "ui/app_list/app_list_item.h"
9 #include "ui/app_list/app_list_model_observer.h"
10 #include "ui/app_list/search_box_model.h"
11 #include "ui/app_list/search_result.h"
12
13 namespace app_list {
14
15 AppListModel::AppListModel()
16     : item_list_(new AppListItemList),
17       search_box_(new SearchBoxModel),
18       results_(new SearchResults),
19       status_(STATUS_NORMAL) {
20   item_list_->AddObserver(this);
21 }
22
23 AppListModel::~AppListModel() {
24   item_list_->RemoveObserver(this);
25 }
26
27 void AppListModel::AddObserver(AppListModelObserver* observer) {
28   observers_.AddObserver(observer);
29 }
30
31 void AppListModel::RemoveObserver(AppListModelObserver* observer) {
32   observers_.RemoveObserver(observer);
33 }
34
35 void AppListModel::SetStatus(Status status) {
36   if (status_ == status)
37     return;
38
39   status_ = status;
40   FOR_EACH_OBSERVER(AppListModelObserver,
41                     observers_,
42                     OnAppListModelStatusChanged());
43 }
44
45 AppListItem* AppListModel::FindItem(const std::string& id) {
46   AppListItem* item = item_list_->FindItem(id);
47   if (item)
48     return item;
49   for (size_t i = 0; i < item_list_->item_count(); ++i) {
50     AppListItem* child_item = item_list_->item_at(i)->FindChildItem(id);
51     if (child_item)
52       return child_item;
53   }
54   return NULL;
55 }
56
57 AppListFolderItem* AppListModel::FindFolderItem(const std::string& id) {
58   AppListItem* item = item_list_->FindItem(id);
59   if (item && item->GetItemType() == AppListFolderItem::kItemType)
60     return static_cast<AppListFolderItem*>(item);
61   DCHECK(!item);
62   return NULL;
63 }
64
65 AppListItem* AppListModel::AddItem(scoped_ptr<AppListItem> item) {
66   DCHECK(!item->IsInFolder());
67   DCHECK(!item_list()->FindItem(item->id()));
68   return AddItemToItemListAndNotify(item.Pass());
69 }
70
71 AppListItem* AppListModel::AddItemToFolder(scoped_ptr<AppListItem> item,
72                                            const std::string& folder_id) {
73   if (folder_id.empty())
74     return AddItem(item.Pass());
75   DCHECK(!item->IsInFolder() || item->folder_id() == folder_id);
76   DCHECK(item->GetItemType() != AppListFolderItem::kItemType);
77   AppListFolderItem* dest_folder = FindOrCreateFolderItem(folder_id);
78   DCHECK(!dest_folder->item_list()->FindItem(item->id()));
79   return AddItemToFolderItemAndNotify(dest_folder, item.Pass());
80 }
81
82 const std::string& AppListModel::MergeItems(const std::string& target_item_id,
83                                             const std::string& source_item_id) {
84   DVLOG(2) << "MergeItems: " << source_item_id << " -> " << target_item_id;
85   // First, remove the source item from the model.
86   scoped_ptr<AppListItem> source_item_ptr =
87       RemoveItem(FindItem(source_item_id));
88
89   // Next, find the target item.
90   AppListItem* target_item = FindItem(target_item_id);
91   DCHECK(target_item);
92   DCHECK(target_item->folder_id().empty());
93
94   // If the target item is a folder, just add |source_item| to it.
95   if (target_item->GetItemType() == AppListFolderItem::kItemType) {
96     AppListFolderItem* target_folder =
97         static_cast<AppListFolderItem*>(target_item);
98     source_item_ptr->set_position(
99         target_folder->item_list()->CreatePositionBefore(
100             syncer::StringOrdinal()));
101     AddItemToFolderItemAndNotify(target_folder, source_item_ptr.Pass());
102     return target_folder->id();
103   }
104
105   // Otherwise, remove the target item from |item_list_|, it will become owned
106   // by the new folder.
107   scoped_ptr<AppListItem> target_item_ptr =
108       item_list_->RemoveItem(target_item_id);
109
110   // Create a new folder in the same location as the target item.
111   scoped_ptr<AppListItem> new_folder_ptr(
112       new AppListFolderItem(AppListFolderItem::GenerateId()));
113   new_folder_ptr->set_position(target_item->position());
114   AppListFolderItem* new_folder = static_cast<AppListFolderItem*>(
115       AddItemToItemListAndNotify(new_folder_ptr.Pass()));
116
117   // Add the items to the new folder.
118   target_item_ptr->set_position(
119       new_folder->item_list()->CreatePositionBefore(
120           syncer::StringOrdinal()));
121   AddItemToFolderItemAndNotify(new_folder, target_item_ptr.Pass());
122   source_item_ptr->set_position(
123       new_folder->item_list()->CreatePositionBefore(
124           syncer::StringOrdinal()));
125   AddItemToFolderItemAndNotify(new_folder, source_item_ptr.Pass());
126
127   return new_folder->id();
128 }
129
130 void AppListModel::MoveItemToFolder(AppListItem* item,
131                                     const std::string& folder_id) {
132   DVLOG(2) << "MoveItemToFolder: " << folder_id
133            << " <- " << item->ToDebugString();
134   if (item->folder_id() == folder_id)
135     return;
136   AppListFolderItem* dest_folder = FindOrCreateFolderItem(folder_id);
137   scoped_ptr<AppListItem> item_ptr = RemoveItem(item);
138   if (dest_folder)
139     AddItemToFolderItemAndNotify(dest_folder, item_ptr.Pass());
140   else
141     AddItemToItemListAndNotifyUpdate(item_ptr.Pass());
142 }
143
144 void AppListModel::MoveItemToFolderAt(AppListItem* item,
145                                       const std::string& folder_id,
146                                       syncer::StringOrdinal position) {
147   DVLOG(2) << "MoveItemToFolderAt: " << folder_id
148            << "[" << position.ToDebugString() << "]"
149            << " <- " << item->ToDebugString();
150   if (item->folder_id() == folder_id)
151     return;
152   AppListFolderItem* dest_folder = FindOrCreateFolderItem(folder_id);
153   scoped_ptr<AppListItem> item_ptr = RemoveItem(item);
154   if (dest_folder) {
155     item_ptr->set_position(
156         dest_folder->item_list()->CreatePositionBefore(position));
157     AddItemToFolderItemAndNotify(dest_folder, item_ptr.Pass());
158   } else {
159     item_ptr->set_position(item_list_->CreatePositionBefore(position));
160     AddItemToItemListAndNotifyUpdate(item_ptr.Pass());
161   }
162 }
163
164 void AppListModel::SetItemPosition(AppListItem* item,
165                                    const syncer::StringOrdinal& new_position) {
166   if (!item->IsInFolder()) {
167     item_list_->SetItemPosition(item, new_position);
168     // Note: this will trigger OnListItemMoved which will signal observers.
169     // (This is done this way because some View code still moves items within
170     // the item list directly).
171     return;
172   }
173   AppListFolderItem* folder = FindFolderItem(item->folder_id());
174   DCHECK(folder);
175   folder->item_list()->SetItemPosition(item, new_position);
176   FOR_EACH_OBSERVER(AppListModelObserver,
177                     observers_,
178                     OnAppListItemUpdated(item));
179 }
180
181 void AppListModel::DeleteItem(const std::string& id) {
182   AppListItem* item = FindItem(id);
183   if (!item)
184     return;
185   if (!item->IsInFolder()) {
186     DCHECK_EQ(0u, item->ChildItemCount())
187         << "Invalid call to DeleteItem for item with children: " << id;
188     FOR_EACH_OBSERVER(AppListModelObserver,
189                       observers_,
190                       OnAppListItemWillBeDeleted(item));
191     item_list_->DeleteItem(id);
192     return;
193   }
194   AppListFolderItem* folder = FindFolderItem(item->folder_id());
195   DCHECK(folder) << "Folder not found for item: " << item->ToDebugString();
196   scoped_ptr<AppListItem> child_item = RemoveItemFromFolder(folder, item);
197   DCHECK_EQ(item, child_item.get());
198   FOR_EACH_OBSERVER(AppListModelObserver,
199                     observers_,
200                     OnAppListItemWillBeDeleted(item));
201   child_item.reset();  // Deletes item.
202 }
203
204 // Private methods
205
206 void AppListModel::OnListItemMoved(size_t from_index,
207                                    size_t to_index,
208                                    AppListItem* item) {
209   FOR_EACH_OBSERVER(AppListModelObserver,
210                     observers_,
211                     OnAppListItemUpdated(item));
212 }
213
214 AppListFolderItem* AppListModel::FindOrCreateFolderItem(
215     const std::string& folder_id) {
216   if (folder_id.empty())
217     return NULL;
218
219   AppListFolderItem* dest_folder = FindFolderItem(folder_id);
220   if (dest_folder)
221     return dest_folder;
222
223   scoped_ptr<AppListFolderItem> new_folder(new AppListFolderItem(folder_id));
224   new_folder->set_position(
225       item_list_->CreatePositionBefore(syncer::StringOrdinal()));
226   AppListItem* new_folder_item =
227       AddItemToItemListAndNotify(new_folder.PassAs<AppListItem>());
228   return static_cast<AppListFolderItem*>(new_folder_item);
229 }
230
231 AppListItem* AppListModel::AddItemToItemListAndNotify(
232     scoped_ptr<AppListItem> item_ptr) {
233   DCHECK(!item_ptr->IsInFolder());
234   AppListItem* item = item_list_->AddItem(item_ptr.Pass());
235   FOR_EACH_OBSERVER(AppListModelObserver,
236                     observers_,
237                     OnAppListItemAdded(item));
238   return item;
239 }
240
241 AppListItem* AppListModel::AddItemToItemListAndNotifyUpdate(
242     scoped_ptr<AppListItem> item_ptr) {
243   DCHECK(!item_ptr->IsInFolder());
244   AppListItem* item = item_list_->AddItem(item_ptr.Pass());
245   FOR_EACH_OBSERVER(AppListModelObserver,
246                     observers_,
247                     OnAppListItemUpdated(item));
248   return item;
249 }
250
251 AppListItem* AppListModel::AddItemToFolderItemAndNotify(
252     AppListFolderItem* folder,
253     scoped_ptr<AppListItem> item_ptr) {
254   AppListItem* item = folder->item_list()->AddItem(item_ptr.Pass());
255   item->set_folder_id(folder->id());
256   FOR_EACH_OBSERVER(AppListModelObserver,
257                     observers_,
258                     OnAppListItemUpdated(item));
259   return item;
260 }
261
262 scoped_ptr<AppListItem> AppListModel::RemoveItem(AppListItem* item) {
263   if (!item->IsInFolder())
264     return item_list_->RemoveItem(item->id());
265
266   AppListFolderItem* folder = FindFolderItem(item->folder_id());
267   DCHECK(folder);
268   return RemoveItemFromFolder(folder, item);
269 }
270
271 scoped_ptr<AppListItem> AppListModel::RemoveItemFromFolder(
272     AppListFolderItem* folder,
273     AppListItem* item) {
274   std::string folder_id = folder->id();
275   DCHECK_EQ(item->folder_id(), folder_id);
276   scoped_ptr<AppListItem> result = folder->item_list()->RemoveItem(item->id());
277   result->set_folder_id("");
278   if (folder->item_list()->item_count() == 0) {
279     DVLOG(2) << "Deleting empty folder: " << folder->ToDebugString();
280     DeleteItem(folder_id);
281   }
282   return result.Pass();
283 }
284
285 }  // namespace app_list