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

Unified 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 side-by-side diff with in-line comments
Download patch
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..d039058de1578d93429b4dbdf148df8eabb601ba 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,196 @@ 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()));
+ if (item_pages_.empty())
+ return AddItemToPageAtIndex(item, 0, 0);
+
+ // Currently items are kept sorted in the model such that for any item A
+ // on page 1 and item B on page 2, A.GetSortOrder() < B.GetSortOrder(). This
+ // also applies to any item A on a page that preceeds B on the same page.
std::string sort_order = item->GetSortOrder();
- // Note: ui::ListModel is not a sorted list.
- size_t index = 0;
- for (; index < apps_->item_count(); ++index) {
- if (sort_order < apps_->GetItemAt(index)->GetSortOrder())
+
+ // First find the page that |item| belongs in.
+ size_t page_idx = 0;
+ for (; page_idx < item_pages_.size() - 1; ++page_idx) {
+ if (sort_order < app_items(page_idx + 1)->GetItemAt(0)->GetSortOrder())
break;
}
- apps_->AddAt(index, item);
+ // Items are kept sorted in a page by convention, but are not logically
+ // gauranteed to be sorted (e.g. if an item's sort order were to change)
+ // so do a linear search instead of using std::find (also the number of items
+ // per page is small and a linear search is simpler).
+ 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;
+ }
+ 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) {
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
+ if (sort_order < apps->GetItemAt(item_idx)->GetSortOrder())
+ break;
+ }
+ 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::GetAppItemsForPage(
+ 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

Powered by Google App Engine
This is Rietveld 408576698