Index: ui/app_list/app_list_model.cc |
diff --git a/ui/app_list/app_list_model.cc b/ui/app_list/app_list_model.cc |
index 246465685685f97cfd3878f592a87f4418d7f4f0..6bb137f1bf8aef2d84229df46eef61a20386c22d 100644 |
--- a/ui/app_list/app_list_model.cc |
+++ b/ui/app_list/app_list_model.cc |
@@ -4,10 +4,12 @@ |
#include "ui/app_list/app_list_model.h" |
+#include "ui/app_list/app_list_constants.h" |
#include "ui/app_list/app_list_item_model.h" |
#include "ui/app_list/app_list_model_observer.h" |
#include "ui/app_list/search_box_model.h" |
#include "ui/app_list/search_result.h" |
+#include "ui/base/models/list_model_observer.h" |
namespace app_list { |
@@ -15,15 +17,56 @@ AppListModel::User::User() : active(false) {} |
AppListModel::User::~User() {} |
+class AppListModel::ItemPage : public ui::ListModelObserver { |
+ public: |
+ ItemPage(AppListModel* model, size_t page_idx) |
+ : model_(model), |
+ page_idx_(page_idx) { |
+ app_items_.AddObserver(this); |
+ } |
+ virtual ~ItemPage() { |
+ app_items_.RemoveObserver(this); |
+ } |
+ virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE { |
+ FOR_EACH_OBSERVER(AppListModelObserver, |
+ model_->observers_, |
+ OnListItemsAdded(page_idx_, start, count)); |
+ } |
+ virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE { |
+ FOR_EACH_OBSERVER(AppListModelObserver, |
+ model_->observers_, |
+ OnListItemsRemoved(page_idx_, start, count)); |
+ } |
+ virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE { |
+ AppListItemModel* item = app_items_.GetItemAt(target_index); |
+ model_->SetItemPosition(item, page_idx_, target_index); |
+ FOR_EACH_OBSERVER(AppListModelObserver, |
+ model_->observers_, |
+ OnListItemMoved(page_idx_, index, target_index)); |
+ } |
+ virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE { |
+ NOTREACHED(); |
+ } |
+ |
+ AppItems* app_items() { return &app_items_; } |
+ |
+ private: |
+ AppListModel* model_; |
+ size_t page_idx_; |
+ AppItems app_items_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ItemPage); |
+}; |
+ |
AppListModel::AppListModel() |
- : apps_(new Apps), |
- search_box_(new SearchBoxModel), |
+ : search_box_(new SearchBoxModel), |
results_(new SearchResults), |
signed_in_(false), |
status_(STATUS_NORMAL) { |
} |
AppListModel::~AppListModel() { |
+ item_pages_.clear(); |
} |
void AppListModel::AddObserver(AppListModelObserver* observer) { |
@@ -62,33 +105,191 @@ void AppListModel::SetSignedIn(bool signed_in) { |
} |
AppListItemModel* AppListModel::FindItem(const std::string& id) { |
- for (size_t i = 0; i < apps_->item_count(); ++i) { |
- AppListItemModel* item = apps_->GetItemAt(i); |
- if (item->id() == id) |
- return item; |
+ for (size_t page = 0; page < item_pages_.size(); ++page) { |
+ AppItems* apps = app_items(page); |
+ for (size_t i = 0; i < apps->item_count(); ++i) { |
+ AppListItemModel* item = apps->GetItemAt(i); |
+ if (item->id() == id) |
+ return item; |
+ } |
} |
return NULL; |
} |
-void AppListModel::AddItem(AppListItemModel* item) { |
+ |
+AppListItemModel* AppListModel::GetItemAt(size_t page_idx, size_t item_idx) { |
+ return app_items(page_idx)->GetItemAt(item_idx); |
+} |
+ |
+size_t AppListModel::AddItem(AppListItemModel* item) { |
+ CHECK(!FindItem(item->id())); |
std::string sort_order = item->GetSortOrder(); |
// Note: ui::ListModel is not a sorted list. |
koz (OOO until 15th September)
2013/10/18 05:17:17
We seem to assume that the items are ordered below
stevenjb
2013/10/18 22:14:26
Yeah, this kind of evolved badly. Made this simple
|
- size_t index = 0; |
- for (; index < apps_->item_count(); ++index) { |
- if (sort_order < apps_->GetItemAt(index)->GetSortOrder()) |
+ size_t page_idx = 0; |
+ size_t item_idx = 0; |
+ bool done = item_pages_.size() == 0; |
koz (OOO until 15th September)
2013/10/18 05:17:17
nit: item_pages_.empty()
stevenjb
2013/10/18 22:14:26
Done.
|
+ while (!done) { |
+ AppItems* apps = app_items(page_idx); |
+ for (; item_idx < apps->item_count(); ++item_idx) { |
+ if (sort_order < apps->GetItemAt(item_idx)->GetSortOrder()) { |
+ done = true; |
+ break; |
+ } |
+ } |
+ if (page_idx < item_pages_.size() - 1) { |
+ ++page_idx; |
+ item_idx = 0; |
+ } else { |
+ break; |
+ } |
+ } |
+ return AddItemToPageAtIndex(item, page_idx, item_idx); |
+} |
+ |
+size_t AppListModel::AddItemToPage(AppListItemModel* item, size_t page_idx) { |
+ CHECK(!FindItem(item->id())); |
+ if (page_idx == item_pages_.size()) { |
+ // OK to add an item to [number of app pages] + 1. |
+ return AddItemToPageAtIndex(item, page_idx, 0); |
+ } |
+ std::string sort_order = item->GetSortOrder(); |
+ AppItems* apps = app_items(page_idx); |
+ size_t item_idx = 0; |
+ for (; item_idx < apps->item_count(); ++item_idx) { |
+ if (sort_order < apps->GetItemAt(item_idx)->GetSortOrder()) |
break; |
} |
- apps_->AddAt(index, item); |
+ return AddItemToPageAtIndex(item, page_idx, item_idx); |
} |
void AppListModel::DeleteItem(const std::string& id) { |
- for (size_t i = 0; i < apps_->item_count(); ++i) { |
- AppListItemModel* item = apps_->GetItemAt(i); |
- if (item->id() == id) { |
- apps_->DeleteAt(i); |
- return; |
+ for (size_t p = 0; p < item_pages_.size(); ++p) { |
+ AppItems* apps = app_items(p); |
+ for (size_t i = 0; i < apps->item_count(); ++i) { |
+ AppListItemModel* item = apps->GetItemAt(i); |
+ if (item->id() == id) { |
+ apps->DeleteAt(i); |
+ if (apps->item_count() == 0) |
+ RemovePage(p); |
+ return; |
+ } |
+ } |
+ } |
+} |
+ |
+void AppListModel::DeleteItemAt(size_t page_idx, size_t item_idx) { |
+ AppItems* apps = app_items(page_idx); |
+ apps->DeleteAt(item_idx); |
+ if (apps->item_count() == 0) |
+ RemovePage(page_idx); |
+} |
+ |
+void AppListModel::MoveItem(size_t page_idx, size_t item_idx, |
+ size_t target_page_idx, size_t target_item_idx) { |
+ VLOG(2) << "MoveItem: " << page_idx << ", " << item_idx |
+ << " -> " << target_page_idx << ", " << target_item_idx; |
+ CHECK_LT(page_idx, item_pages_.size()); |
+ CHECK_LE(item_idx, app_items(page_idx)->item_count()); |
+ if (target_page_idx == page_idx) { |
+ CHECK_LT(target_item_idx, app_items(page_idx)->item_count()); |
+ app_items(page_idx)->Move(item_idx, target_item_idx); |
+ // SetItemPosition will get called by ItemPage::ListItemMoved. |
+ } else { |
+ AppListItemModel* item = app_items(page_idx)->RemoveAt(item_idx); |
+ if (target_page_idx >= item_pages_.size()) { |
+ AddPage(); |
+ CHECK_LT(target_page_idx, item_pages_.size()); |
} |
+ CHECK_LE(target_item_idx, app_items(target_page_idx)->item_count()); |
+ AddItemToPageAtIndex(item, target_page_idx, target_item_idx); |
+ } |
+} |
+ |
+// static |
+size_t AppListModel::GetNumAppsPerPage() { |
+ return kPreferredCols * kPreferredRows; |
+} |
+ |
+size_t AppListModel::GetNumAppPages() const { |
+ return item_pages_.size(); |
+} |
+ |
+const AppListModel::AppItems& AppListModel::GetAppItems(size_t page_idx) const { |
+ CHECK_LT(page_idx, item_pages_.size()); |
+ return *(item_pages_[page_idx]->app_items()); |
+} |
+ |
+AppListModel::AppItems* AppListModel::app_items(size_t page_idx) { |
+ CHECK_LT(page_idx, item_pages_.size()); |
+ return item_pages_[page_idx]->app_items(); |
+} |
+ |
+void AppListModel::AddPage() { |
+ size_t page_idx = item_pages_.size(); |
+ item_pages_.push_back(new ItemPage(this, page_idx)); |
+ // Notify page added |
+} |
+ |
+void AppListModel::RemovePage(size_t page_idx) { |
+ item_pages_.erase(item_pages_.begin() + page_idx); |
+ // Notify page removed |
+} |
+ |
+size_t AppListModel::AddItemToPageAtIndex(AppListItemModel* item, |
+ size_t page_idx, size_t item_idx) { |
+ if (item_idx >= GetNumAppsPerPage()) { |
+ ++page_idx; |
+ item_idx = 0; |
+ } |
+ if (page_idx >= item_pages_.size()) |
+ AddPage(); |
+ |
+ AppItems* apps = app_items(page_idx); |
+ apps->AddAt(item_idx, item); |
+ VLOG(2) << "AddItemToPage: " << item->id() |
+ << " Page: " << page_idx << " Idx: " << item_idx |
+ << " / " << apps->item_count(); |
+ SetItemPosition(item, page_idx, item_idx); |
+ if (apps->item_count() > GetNumAppsPerPage()) { |
+ AppListItemModel* last_item = apps->RemoveAt(apps->item_count() - 1); |
+ CHECK_EQ(GetNumAppsPerPage(), apps->item_count()); |
+ if (++page_idx >= item_pages_.size()) |
+ AddPage(); |
+ AddItemToPageAtIndex(last_item, page_idx, 0); |
+ } |
+ return page_idx; |
+} |
+ |
+void AppListModel::SetItemPosition(AppListItemModel* item, |
+ size_t page_idx, size_t item_idx) { |
+ VLOG(2) << " SetItemPosition: " << item->id() |
+ << " Page: " << page_idx << " Idx: " << item_idx; |
+ AppItems* apps = app_items(page_idx); |
+ AppListItemModel* next = NULL; |
+ if (item_idx + 1 < apps->item_count()) { |
+ next = apps->GetItemAt(item_idx + 1); |
+ } else if (page_idx < item_pages_.size() - 1) { |
+ AppItems* next_apps = app_items(page_idx + 1); |
+ CHECK(next_apps->item_count() > 0); |
+ next = next_apps->GetItemAt(0); |
+ } |
+ AppListItemModel* prev = NULL; |
+ if (item_idx > 0) { |
+ prev = apps->GetItemAt(item_idx - 1); |
+ } else if (page_idx > 0) { |
+ AppItems* prev_apps = app_items(page_idx - 1); |
+ CHECK(prev_apps->item_count() > 0); |
+ prev = prev_apps->GetItemAt(prev_apps->item_count() - 1); |
+ } |
+ syncer::StringOrdinal new_position; |
+ if (prev) { |
+ new_position = next ? prev->position().CreateBetween(next->position()) |
+ : prev->position().CreateAfter(); |
+ } else { |
+ new_position = next ? next->position().CreateBefore() |
+ : syncer::StringOrdinal::CreateInitialOrdinal(); |
} |
+ item->set_position(new_position); |
} |
} // namespace app_list |