Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: ui/app_list/app_list_model.cc

Issue 27438002: Store AppItems as pages in AppListModel. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/app_list/app_list_model.h" 5 #include "ui/app_list/app_list_model.h"
6 6
7 #include "ui/app_list/app_list_constants.h"
7 #include "ui/app_list/app_list_item_model.h" 8 #include "ui/app_list/app_list_item_model.h"
8 #include "ui/app_list/app_list_model_observer.h" 9 #include "ui/app_list/app_list_model_observer.h"
9 #include "ui/app_list/search_box_model.h" 10 #include "ui/app_list/search_box_model.h"
10 #include "ui/app_list/search_result.h" 11 #include "ui/app_list/search_result.h"
12 #include "ui/base/models/list_model_observer.h"
11 13
12 namespace app_list { 14 namespace app_list {
13 15
14 AppListModel::User::User() : active(false) {} 16 AppListModel::User::User() : active(false) {}
15 17
16 AppListModel::User::~User() {} 18 AppListModel::User::~User() {}
17 19
20 class AppListModel::ItemPage : public ui::ListModelObserver {
21 public:
22 ItemPage(AppListModel* model, size_t page_idx)
23 : model_(model),
24 page_idx_(page_idx) {
25 app_items_.AddObserver(this);
26 }
27 virtual ~ItemPage() {
28 app_items_.RemoveObserver(this);
29 }
30 virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE {
31 FOR_EACH_OBSERVER(AppListModelObserver,
32 model_->observers_,
33 OnListItemsAdded(page_idx_, start, count));
34 }
35 virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE {
36 FOR_EACH_OBSERVER(AppListModelObserver,
37 model_->observers_,
38 OnListItemsRemoved(page_idx_, start, count));
39 }
40 virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE {
41 AppListItemModel* item = app_items_.GetItemAt(target_index);
42 model_->SetItemPosition(item, page_idx_, target_index);
43 FOR_EACH_OBSERVER(AppListModelObserver,
44 model_->observers_,
45 OnListItemMoved(page_idx_, index, target_index));
46 }
47 virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE {
48 NOTREACHED();
49 }
50
51 AppItems* app_items() { return &app_items_; }
52
53 private:
54 AppListModel* model_;
55 size_t page_idx_;
56 AppItems app_items_;
57
58 DISALLOW_COPY_AND_ASSIGN(ItemPage);
59 };
60
18 AppListModel::AppListModel() 61 AppListModel::AppListModel()
19 : apps_(new Apps), 62 : search_box_(new SearchBoxModel),
20 search_box_(new SearchBoxModel),
21 results_(new SearchResults), 63 results_(new SearchResults),
22 signed_in_(false), 64 signed_in_(false),
23 status_(STATUS_NORMAL) { 65 status_(STATUS_NORMAL) {
24 } 66 }
25 67
26 AppListModel::~AppListModel() { 68 AppListModel::~AppListModel() {
69 item_pages_.clear();
27 } 70 }
28 71
29 void AppListModel::AddObserver(AppListModelObserver* observer) { 72 void AppListModel::AddObserver(AppListModelObserver* observer) {
30 observers_.AddObserver(observer); 73 observers_.AddObserver(observer);
31 } 74 }
32 75
33 void AppListModel::RemoveObserver(AppListModelObserver* observer) { 76 void AppListModel::RemoveObserver(AppListModelObserver* observer) {
34 observers_.RemoveObserver(observer); 77 observers_.RemoveObserver(observer);
35 } 78 }
36 79
(...skipping 18 matching lines...) Expand all
55 if (signed_in_ == signed_in) 98 if (signed_in_ == signed_in)
56 return; 99 return;
57 100
58 signed_in_ = signed_in; 101 signed_in_ = signed_in;
59 FOR_EACH_OBSERVER(AppListModelObserver, 102 FOR_EACH_OBSERVER(AppListModelObserver,
60 observers_, 103 observers_,
61 OnAppListModelSigninStatusChanged()); 104 OnAppListModelSigninStatusChanged());
62 } 105 }
63 106
64 AppListItemModel* AppListModel::FindItem(const std::string& id) { 107 AppListItemModel* AppListModel::FindItem(const std::string& id) {
65 for (size_t i = 0; i < apps_->item_count(); ++i) { 108 for (size_t page = 0; page < item_pages_.size(); ++page) {
66 AppListItemModel* item = apps_->GetItemAt(i); 109 AppItems* apps = app_items(page);
67 if (item->id() == id) 110 for (size_t i = 0; i < apps->item_count(); ++i) {
68 return item; 111 AppListItemModel* item = apps->GetItemAt(i);
112 if (item->id() == id)
113 return item;
114 }
69 } 115 }
70 return NULL; 116 return NULL;
71 } 117 }
72 118
73 void AppListModel::AddItem(AppListItemModel* item) { 119
120 AppListItemModel* AppListModel::GetItemAt(size_t page_idx, size_t item_idx) {
121 return app_items(page_idx)->GetItemAt(item_idx);
122 }
123
124 size_t AppListModel::AddItem(AppListItemModel* item) {
125 CHECK(!FindItem(item->id()));
126 if (item_pages_.empty())
127 return AddItemToPageAtIndex(item, 0, 0);
128
129 // Currently items are kept sorted in the model such that for any item A
130 // on page 1 and item B on page 2, A.GetSortOrder() < B.GetSortOrder(). This
131 // also applies to any item A on a page that preceeds B on the same page.
74 std::string sort_order = item->GetSortOrder(); 132 std::string sort_order = item->GetSortOrder();
75 // Note: ui::ListModel is not a sorted list. 133
76 size_t index = 0; 134 // First find the page that |item| belongs in.
77 for (; index < apps_->item_count(); ++index) { 135 size_t page_idx = 0;
78 if (sort_order < apps_->GetItemAt(index)->GetSortOrder()) 136 for (; page_idx < item_pages_.size() - 1; ++page_idx) {
137 if (sort_order < app_items(page_idx + 1)->GetItemAt(0)->GetSortOrder())
79 break; 138 break;
80 } 139 }
81 apps_->AddAt(index, item); 140 // Items are kept sorted in a page by convention, but are not logically
141 // gauranteed to be sorted (e.g. if an item's sort order were to change)
142 // so do a linear search instead of using std::find (also the number of items
143 // per page is small and a linear search is simpler).
144 AppItems* apps = app_items(page_idx);
145 size_t item_idx = 0;
146 for (; item_idx < apps->item_count(); ++item_idx) {
147 if (sort_order < apps->GetItemAt(item_idx)->GetSortOrder())
148 break;
149 }
150 return AddItemToPageAtIndex(item, page_idx, item_idx);
151 }
152
153 size_t AppListModel::AddItemToPage(AppListItemModel* item, size_t page_idx) {
154 CHECK(!FindItem(item->id()));
155 if (page_idx == item_pages_.size()) {
156 // OK to add an item to [number of app pages] + 1.
157 return AddItemToPageAtIndex(item, page_idx, 0);
158 }
159 std::string sort_order = item->GetSortOrder();
160 AppItems* apps = app_items(page_idx);
161 size_t item_idx = 0;
162 for (; item_idx < apps->item_count(); ++item_idx) {
xiyuan 2013/10/18 23:04:08 Can we make this loop of insertion an item part of
stevenjb 2013/10/19 01:04:43 That sounds reasonable. I kind of wanted to keep t
163 if (sort_order < apps->GetItemAt(item_idx)->GetSortOrder())
164 break;
165 }
166 return AddItemToPageAtIndex(item, page_idx, item_idx);
82 } 167 }
83 168
84 void AppListModel::DeleteItem(const std::string& id) { 169 void AppListModel::DeleteItem(const std::string& id) {
85 for (size_t i = 0; i < apps_->item_count(); ++i) { 170 for (size_t p = 0; p < item_pages_.size(); ++p) {
86 AppListItemModel* item = apps_->GetItemAt(i); 171 AppItems* apps = app_items(p);
87 if (item->id() == id) { 172 for (size_t i = 0; i < apps->item_count(); ++i) {
88 apps_->DeleteAt(i); 173 AppListItemModel* item = apps->GetItemAt(i);
89 return; 174 if (item->id() == id) {
175 apps->DeleteAt(i);
176 if (apps->item_count() == 0)
177 RemovePage(p);
178 return;
179 }
90 } 180 }
91 } 181 }
92 } 182 }
93 183
184 void AppListModel::DeleteItemAt(size_t page_idx, size_t item_idx) {
185 AppItems* apps = app_items(page_idx);
186 apps->DeleteAt(item_idx);
187 if (apps->item_count() == 0)
188 RemovePage(page_idx);
189 }
190
191 void AppListModel::MoveItem(size_t page_idx, size_t item_idx,
192 size_t target_page_idx, size_t target_item_idx) {
193 VLOG(2) << "MoveItem: " << page_idx << ", " << item_idx
194 << " -> " << target_page_idx << ", " << target_item_idx;
195 CHECK_LT(page_idx, item_pages_.size());
196 CHECK_LE(item_idx, app_items(page_idx)->item_count());
197 if (target_page_idx == page_idx) {
198 CHECK_LT(target_item_idx, app_items(page_idx)->item_count());
199 app_items(page_idx)->Move(item_idx, target_item_idx);
200 // SetItemPosition will get called by ItemPage::ListItemMoved.
201 } else {
202 AppListItemModel* item = app_items(page_idx)->RemoveAt(item_idx);
203 if (target_page_idx >= item_pages_.size()) {
204 AddPage();
205 CHECK_LT(target_page_idx, item_pages_.size());
206 }
207 CHECK_LE(target_item_idx, app_items(target_page_idx)->item_count());
208 AddItemToPageAtIndex(item, target_page_idx, target_item_idx);
209 }
210 }
211
212 // static
213 size_t AppListModel::GetNumAppsPerPage() {
214 return kPreferredCols * kPreferredRows;
215 }
216
217 size_t AppListModel::GetNumAppPages() const {
218 return item_pages_.size();
219 }
220
221 const AppListModel::AppItems& AppListModel::GetAppItemsForPage(
222 size_t page_idx) const {
223 CHECK_LT(page_idx, item_pages_.size());
224 return *(item_pages_[page_idx]->app_items());
225 }
226
227 AppListModel::AppItems* AppListModel::app_items(size_t page_idx) {
228 CHECK_LT(page_idx, item_pages_.size());
229 return item_pages_[page_idx]->app_items();
230 }
231
232 void AppListModel::AddPage() {
233 size_t page_idx = item_pages_.size();
234 item_pages_.push_back(new ItemPage(this, page_idx));
235 // Notify page added
236 }
237
238 void AppListModel::RemovePage(size_t page_idx) {
239 item_pages_.erase(item_pages_.begin() + page_idx);
240 // Notify page removed
241 }
242
243 size_t AppListModel::AddItemToPageAtIndex(AppListItemModel* item,
244 size_t page_idx, size_t item_idx) {
245 if (item_idx >= GetNumAppsPerPage()) {
246 ++page_idx;
247 item_idx = 0;
248 }
249 if (page_idx >= item_pages_.size())
250 AddPage();
251
252 AppItems* apps = app_items(page_idx);
253 apps->AddAt(item_idx, item);
254 VLOG(2) << "AddItemToPage: " << item->id()
255 << " Page: " << page_idx << " Idx: " << item_idx
256 << " / " << apps->item_count();
257 SetItemPosition(item, page_idx, item_idx);
258 if (apps->item_count() > GetNumAppsPerPage()) {
259 AppListItemModel* last_item = apps->RemoveAt(apps->item_count() - 1);
260 CHECK_EQ(GetNumAppsPerPage(), apps->item_count());
261 if (++page_idx >= item_pages_.size())
262 AddPage();
263 AddItemToPageAtIndex(last_item, page_idx, 0);
264 }
265 return page_idx;
266 }
267
268 void AppListModel::SetItemPosition(AppListItemModel* item,
269 size_t page_idx, size_t item_idx) {
270 VLOG(2) << " SetItemPosition: " << item->id()
271 << " Page: " << page_idx << " Idx: " << item_idx;
272 AppItems* apps = app_items(page_idx);
273 AppListItemModel* next = NULL;
274 if (item_idx + 1 < apps->item_count()) {
275 next = apps->GetItemAt(item_idx + 1);
276 } else if (page_idx < item_pages_.size() - 1) {
277 AppItems* next_apps = app_items(page_idx + 1);
278 CHECK(next_apps->item_count() > 0);
279 next = next_apps->GetItemAt(0);
280 }
281 AppListItemModel* prev = NULL;
282 if (item_idx > 0) {
283 prev = apps->GetItemAt(item_idx - 1);
284 } else if (page_idx > 0) {
285 AppItems* prev_apps = app_items(page_idx - 1);
286 CHECK(prev_apps->item_count() > 0);
287 prev = prev_apps->GetItemAt(prev_apps->item_count() - 1);
288 }
289 syncer::StringOrdinal new_position;
290 if (prev) {
291 new_position = next ? prev->position().CreateBetween(next->position())
292 : prev->position().CreateAfter();
293 } else {
294 new_position = next ? next->position().CreateBefore()
295 : syncer::StringOrdinal::CreateInitialOrdinal();
296 }
297 item->set_position(new_position);
298 }
299
94 } // namespace app_list 300 } // namespace app_list
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698