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.
5 #include "ui/app_list/app_list_model.h"
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"
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);
23 AppListModel::~AppListModel() {
24 item_list_->RemoveObserver(this);
27 void AppListModel::AddObserver(AppListModelObserver* observer) {
28 observers_.AddObserver(observer);
31 void AppListModel::RemoveObserver(AppListModelObserver* observer) {
32 observers_.RemoveObserver(observer);
35 void AppListModel::SetStatus(Status status) {
36 if (status_ == status)
40 FOR_EACH_OBSERVER(AppListModelObserver,
42 OnAppListModelStatusChanged());
45 AppListItem* AppListModel::FindItem(const std::string& id) {
46 AppListItem* item = item_list_->FindItem(id);
49 for (size_t i = 0; i < item_list_->item_count(); ++i) {
50 AppListItem* child_item = item_list_->item_at(i)->FindChildItem(id);
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);
65 AppListItem* AppListModel::AddItem(scoped_ptr<AppListItem> item) {
66 DCHECK(!item->IsInFolder());
67 DCHECK(!item_list()->FindItem(item->id()));
68 return AddItemToItemListAndNotify(item.Pass());
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());
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));
89 // Next, find the target item.
90 AppListItem* target_item = FindItem(target_item_id);
92 DCHECK(target_item->folder_id().empty());
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();
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);
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()));
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());
127 return new_folder->id();
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)
136 AppListFolderItem* dest_folder = FindOrCreateFolderItem(folder_id);
137 scoped_ptr<AppListItem> item_ptr = RemoveItem(item);
139 AddItemToFolderItemAndNotify(dest_folder, item_ptr.Pass());
141 AddItemToItemListAndNotifyUpdate(item_ptr.Pass());
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)
152 AppListFolderItem* dest_folder = FindOrCreateFolderItem(folder_id);
153 scoped_ptr<AppListItem> item_ptr = RemoveItem(item);
155 item_ptr->set_position(
156 dest_folder->item_list()->CreatePositionBefore(position));
157 AddItemToFolderItemAndNotify(dest_folder, item_ptr.Pass());
159 item_ptr->set_position(item_list_->CreatePositionBefore(position));
160 AddItemToItemListAndNotifyUpdate(item_ptr.Pass());
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).
173 AppListFolderItem* folder = FindFolderItem(item->folder_id());
175 folder->item_list()->SetItemPosition(item, new_position);
176 FOR_EACH_OBSERVER(AppListModelObserver,
178 OnAppListItemUpdated(item));
181 void AppListModel::DeleteItem(const std::string& id) {
182 AppListItem* item = FindItem(id);
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,
190 OnAppListItemWillBeDeleted(item));
191 item_list_->DeleteItem(id);
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,
200 OnAppListItemWillBeDeleted(item));
201 child_item.reset(); // Deletes item.
206 void AppListModel::OnListItemMoved(size_t from_index,
209 FOR_EACH_OBSERVER(AppListModelObserver,
211 OnAppListItemUpdated(item));
214 AppListFolderItem* AppListModel::FindOrCreateFolderItem(
215 const std::string& folder_id) {
216 if (folder_id.empty())
219 AppListFolderItem* dest_folder = FindFolderItem(folder_id);
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);
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,
237 OnAppListItemAdded(item));
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,
247 OnAppListItemUpdated(item));
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,
258 OnAppListItemUpdated(item));
262 scoped_ptr<AppListItem> AppListModel::RemoveItem(AppListItem* item) {
263 if (!item->IsInFolder())
264 return item_list_->RemoveItem(item->id());
266 AppListFolderItem* folder = FindFolderItem(item->folder_id());
268 return RemoveItemFromFolder(folder, item);
271 scoped_ptr<AppListItem> AppListModel::RemoveItemFromFolder(
272 AppListFolderItem* folder,
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);
282 return result.Pass();
285 } // namespace app_list