summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-30 21:09:31 +0000
committerstevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-30 21:09:31 +0000
commitae976573b41eec9ded0fe4354a4dd1406341da5a (patch)
tree8164ab8f8646057bc3fb98bba915182e6ab51539
parentcfee2746954c8c0eb0fe3957e7f398ad97e766fa (diff)
downloadchromium_src-ae976573b41eec9ded0fe4354a4dd1406341da5a.zip
chromium_src-ae976573b41eec9ded0fe4354a4dd1406341da5a.tar.gz
chromium_src-ae976573b41eec9ded0fe4354a4dd1406341da5a.tar.bz2
Add |position| to AppListItemModel and add AppListItemList (Take 2)
This adds a |position_| member to AppListItemModel in preparation for syncing the app list independent of extensions. It also moves some common code in AppListModel and AppListFolderItem into AppListItemList, which ensures that |position_| is keept up to date. This implementation keeps all position maintenance in AppListItemList and uses AppListItemListObserver to allow ExtensonAppItem to (temporarily) override the positioning logic. BUG=305024 For as/shell OWNER: R=jennyz@chromium.org, xiyuan@chromium.org TBR=jamescook@chromium.org Review URL: https://codereview.chromium.org/50003002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231923 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/shell/app_list.cc7
-rw-r--r--chrome/browser/ui/app_list/extension_app_item.cc22
-rw-r--r--chrome/browser/ui/app_list/extension_app_item.h9
-rw-r--r--chrome/browser/ui/app_list/extension_app_model_builder.cc48
-rw-r--r--chrome/browser/ui/app_list/extension_app_model_builder.h11
-rw-r--r--chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc10
-rw-r--r--chrome/browser/ui/app_list/fast_show_pickler.cc16
-rw-r--r--chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc32
-rw-r--r--ui/app_list/DEPS1
-rw-r--r--ui/app_list/app_list.gyp3
-rw-r--r--ui/app_list/app_list_folder_item.cc62
-rw-r--r--ui/app_list/app_list_folder_item.h35
-rw-r--r--ui/app_list/app_list_item_list.cc132
-rw-r--r--ui/app_list/app_list_item_list.h72
-rw-r--r--ui/app_list/app_list_item_list_observer.h34
-rw-r--r--ui/app_list/app_list_item_model.cc4
-rw-r--r--ui/app_list/app_list_item_model.h13
-rw-r--r--ui/app_list/app_list_model.cc32
-rw-r--r--ui/app_list/app_list_model.h25
-rw-r--r--ui/app_list/app_list_model_unittest.cc164
-rw-r--r--ui/app_list/cocoa/apps_grid_controller.h2
-rw-r--r--ui/app_list/cocoa/apps_grid_controller.mm77
-rw-r--r--ui/app_list/cocoa/apps_grid_controller_unittest.mm84
-rw-r--r--ui/app_list/cocoa/apps_grid_view_item.mm2
-rw-r--r--ui/app_list/test/app_list_test_model.cc24
-rw-r--r--ui/app_list/test/app_list_test_model.h2
-rw-r--r--ui/app_list/views/app_list_folder_view.cc3
-rw-r--r--ui/app_list/views/app_list_item_view.h2
-rw-r--r--ui/app_list/views/app_list_main_view.cc4
-rw-r--r--ui/app_list/views/apps_container_view.cc5
-rw-r--r--ui/app_list/views/apps_grid_view.cc73
-rw-r--r--ui/app_list/views/apps_grid_view.h22
-rw-r--r--ui/app_list/views/apps_grid_view_unittest.cc12
33 files changed, 705 insertions, 339 deletions
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
index 7448de4..fe62d21 100644
--- a/ash/shell/app_list.cc
+++ b/ash/shell/app_list.cc
@@ -16,6 +16,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "ui/app_list/app_list_item_list.h"
#include "ui/app_list/app_list_item_model.h"
#include "ui/app_list/app_list_model.h"
#include "ui/app_list/app_list_view_delegate.h"
@@ -195,14 +196,14 @@ class ExampleAppListViewDelegate : public app_list::AppListViewDelegate {
ExampleAppListViewDelegate() : model_(NULL) {}
private:
- void PopulateApps(app_list::AppListModel::Apps* apps) {
+ void PopulateApps(app_list::AppListItemList* item_list) {
for (int i = 0;
i < static_cast<int>(WindowTypeLauncherItem::LAST_TYPE);
++i) {
WindowTypeLauncherItem::Type type =
static_cast<WindowTypeLauncherItem::Type>(i);
std::string id = base::StringPrintf("%d", i);
- apps->Add(new WindowTypeLauncherItem(id, type));
+ item_list->AddItem(new WindowTypeLauncherItem(id, type));
}
}
@@ -233,7 +234,7 @@ class ExampleAppListViewDelegate : public app_list::AppListViewDelegate {
virtual void InitModel(app_list::AppListModel* model) OVERRIDE {
model_ = model;
- PopulateApps(model_->apps());
+ PopulateApps(model_->item_list());
DecorateSearchBox(model_->search_box());
}
diff --git a/chrome/browser/ui/app_list/extension_app_item.cc b/chrome/browser/ui/app_list/extension_app_item.cc
index 20d3f1c..dbeaa11 100644
--- a/chrome/browser/ui/app_list/extension_app_item.cc
+++ b/chrome/browser/ui/app_list/extension_app_item.cc
@@ -85,13 +85,7 @@ ExtensionAppItem::ExtensionAppItem(Profile* profile,
Reload();
GetExtensionSorting(profile_)->EnsureValidOrdinals(extension_id_,
syncer::StringOrdinal());
- // Set |sort_order_|. Use '_' as a separator to ensure a_a preceeds aa_a.
- // (StringOrdinal uses 'a'-'z').
- const syncer::StringOrdinal& page =
- GetExtensionSorting(profile_)->GetPageOrdinal(extension_id_);
- const syncer::StringOrdinal& launch =
- GetExtensionSorting(profile_)->GetAppLaunchOrdinal(extension_id_);
- sort_order_ = page.ToInternalValue() + '_' + launch.ToInternalValue();
+ UpdatePositionFromExtensionOrdering();
}
ExtensionAppItem::~ExtensionAppItem() {
@@ -169,6 +163,7 @@ void ExtensionAppItem::Move(const ExtensionAppItem* prev,
service->extension_prefs()->SetAppDraggedByUser(extension_id_);
sorting->SetPageOrdinal(extension_id_, page);
service->OnExtensionMoved(extension_id_, prev_id, next_id);
+ UpdatePositionFromExtensionOrdering();
}
const Extension* ExtensionAppItem::GetExtension() const {
@@ -240,10 +235,6 @@ void ExtensionAppItem::ExtensionEnableFlowAborted(bool user_initiated) {
controller_->OnCloseExtensionPrompt();
}
-std::string ExtensionAppItem::GetSortOrder() const {
- return sort_order_;
-}
-
void ExtensionAppItem::Activate(int event_flags) {
// |extension| could be NULL when it is being unloaded for updating.
const Extension* extension = GetExtension();
@@ -280,3 +271,12 @@ const char* ExtensionAppItem::GetAppType() const {
void ExtensionAppItem::ExecuteLaunchCommand(int event_flags) {
Launch(event_flags);
}
+
+void ExtensionAppItem::UpdatePositionFromExtensionOrdering() {
+ const syncer::StringOrdinal& page =
+ GetExtensionSorting(profile_)->GetPageOrdinal(extension_id_);
+ const syncer::StringOrdinal& launch =
+ GetExtensionSorting(profile_)->GetAppLaunchOrdinal(extension_id_);
+ set_position(syncer::StringOrdinal(
+ page.ToInternalValue() + launch.ToInternalValue()));
+}
diff --git a/chrome/browser/ui/app_list/extension_app_item.h b/chrome/browser/ui/app_list/extension_app_item.h
index eb56f42..362a016 100644
--- a/chrome/browser/ui/app_list/extension_app_item.h
+++ b/chrome/browser/ui/app_list/extension_app_item.h
@@ -85,7 +85,6 @@ class ExtensionAppItem : public app_list::AppListItemModel,
virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE;
// Overridden from AppListItemModel:
- virtual std::string GetSortOrder() const OVERRIDE;
virtual void Activate(int event_flags) OVERRIDE;
virtual ui::MenuModel* GetContextMenuModel() OVERRIDE;
virtual const char* GetAppType() const OVERRIDE;
@@ -93,6 +92,9 @@ class ExtensionAppItem : public app_list::AppListItemModel,
// Overridden from app_list::AppContextMenuDelegate:
virtual void ExecuteLaunchCommand(int event_flags) OVERRIDE;
+ // Set the position from the extension ordering.
+ void UpdatePositionFromExtensionOrdering();
+
Profile* profile_;
const std::string extension_id_;
AppListControllerDelegate* controller_;
@@ -110,11 +112,6 @@ class ExtensionAppItem : public app_list::AppListItemModel,
// Whether or not this app is a platform app.
bool is_platform_app_;
- // Cache initial sort order. Sort order is not synced with the extensions
- // app ordering once apps are loaded. This will be ignored (or overridden)
- // once the app list is synced.
- std::string sort_order_;
-
DISALLOW_COPY_AND_ASSIGN(ExtensionAppItem);
};
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder.cc b/chrome/browser/ui/app_list/extension_app_model_builder.cc
index 1f17f6d..63e29a8 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/extension_app_model_builder.cc
@@ -48,13 +48,13 @@ ExtensionAppModelBuilder::ExtensionAppModelBuilder(
model_(model),
highlighted_app_pending_(false),
tracker_(NULL) {
- model_->apps()->AddObserver(this);
+ model_->item_list()->AddObserver(this);
SwitchProfile(profile); // Builds the model.
}
ExtensionAppModelBuilder::~ExtensionAppModelBuilder() {
OnShutdown();
- model_->apps()->RemoveObserver(this);
+ model_->item_list()->RemoveObserver(this);
}
void ExtensionAppModelBuilder::OnBeginExtensionInstall(
@@ -123,7 +123,7 @@ void ExtensionAppModelBuilder::OnExtensionUnloaded(const Extension* extension) {
void ExtensionAppModelBuilder::OnExtensionUninstalled(
const Extension* extension) {
- model_->DeleteItem(extension->id());
+ model_->item_list()->DeleteItem(extension->id());
}
void ExtensionAppModelBuilder::OnAppsReordered() {
@@ -162,12 +162,7 @@ void ExtensionAppModelBuilder::SwitchProfile(Profile* profile) {
profile_ = profile;
// Delete any extension apps.
- app_list::AppListModel::Apps* app_list = model_->apps();
- for (int i = static_cast<int>(app_list->item_count()) - 1; i >= 0; --i) {
- app_list::AppListItemModel* item = app_list->GetItemAt(i);
- if (item->GetAppType() == ExtensionAppItem::kAppType)
- app_list->DeleteAt(i);
- }
+ model_->item_list()->DeleteItemsByType(ExtensionAppItem::kAppType);
if (tracker_)
tracker_->RemoveObserver(this);
@@ -204,7 +199,7 @@ void ExtensionAppModelBuilder::PopulateApps() {
}
void ExtensionAppModelBuilder::InsertApp(ExtensionAppItem* app) {
- model_->AddItem(app);
+ model_->item_list()->AddItem(app);
}
void ExtensionAppModelBuilder::SetHighlightedApp(
@@ -223,7 +218,8 @@ void ExtensionAppModelBuilder::SetHighlightedApp(
ExtensionAppItem* ExtensionAppModelBuilder::GetExtensionAppItem(
const std::string& extension_id) {
- app_list::AppListItemModel* item = model_->FindItem(extension_id);
+ app_list::AppListItemModel* item =
+ model_->item_list()->FindItem(extension_id);
LOG_IF(ERROR, item &&
item->GetAppType() != ExtensionAppItem::kAppType)
<< "App Item matching id: " << extension_id
@@ -242,39 +238,33 @@ void ExtensionAppModelBuilder::UpdateHighlight() {
highlighted_app_pending_ = false;
}
-void ExtensionAppModelBuilder::ListItemsAdded(size_t start, size_t count) {
-}
-
-void ExtensionAppModelBuilder::ListItemsRemoved(size_t start, size_t count) {
-}
-
-void ExtensionAppModelBuilder::ListItemMoved(size_t index,
- size_t target_index) {
- app_list::AppListModel::Apps* app_list = model_->apps();
- app_list::AppListItemModel* item = app_list->GetItemAt(target_index);
+void ExtensionAppModelBuilder::OnListItemMoved(
+ size_t from_index,
+ size_t to_index,
+ app_list::AppListItemModel* item) {
+ // This will get called from AppListItemList::ListItemMoved after
+ // set_position is called for the item.
+ app_list::AppListItemList* item_list = model_->item_list();
if (item->GetAppType() != ExtensionAppItem::kAppType)
return;
ExtensionAppItem* prev = NULL;
- for (size_t idx = target_index; idx > 1; --idx) {
- app_list::AppListItemModel* item = app_list->GetItemAt(idx - 1);
+ for (size_t idx = to_index; idx > 0; --idx) {
+ app_list::AppListItemModel* item = item_list->item_at(idx - 1);
if (item->GetAppType() == ExtensionAppItem::kAppType) {
prev = static_cast<ExtensionAppItem*>(item);
break;
}
}
ExtensionAppItem* next = NULL;
- for (size_t idx = target_index; idx < app_list->item_count() - 1; ++idx) {
- app_list::AppListItemModel* item = app_list->GetItemAt(idx + 1);
+ for (size_t idx = to_index; idx < item_list->item_count() - 1; ++idx) {
+ app_list::AppListItemModel* item = item_list->item_at(idx + 1);
if (item->GetAppType() == ExtensionAppItem::kAppType) {
next = static_cast<ExtensionAppItem*>(item);
break;
}
}
+ // item->Move will call set_position, overriding the item's position.
if (prev || next)
static_cast<ExtensionAppItem*>(item)->Move(prev, next);
}
-
-void ExtensionAppModelBuilder::ListItemsChanged(size_t start, size_t count) {
- NOTREACHED();
-}
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder.h b/chrome/browser/ui/app_list/extension_app_model_builder.h
index 50cfb9e..48452ee 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder.h
+++ b/chrome/browser/ui/app_list/extension_app_model_builder.h
@@ -30,7 +30,7 @@ class ImageSkia;
// This class populates and maintains the given |model| with information from
// |profile|.
class ExtensionAppModelBuilder : public extensions::InstallObserver,
- public ui::ListModelObserver {
+ public app_list::AppListItemListObserver {
public:
ExtensionAppModelBuilder(Profile* profile,
app_list::AppListModel* model,
@@ -65,11 +65,10 @@ class ExtensionAppModelBuilder : public extensions::InstallObserver,
const std::string& extension_id) OVERRIDE;
virtual void OnShutdown() OVERRIDE;
- // ui::ListModelObserver
- virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE;
- virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE;
- virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE;
- virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE;
+ // AppListItemListObserver
+ virtual void OnListItemMoved(size_t from_index,
+ size_t to_index,
+ app_list::AppListItemModel* item) OVERRIDE;
// Adds apps in |extensions| to |apps|.
void AddApps(const ExtensionSet* extensions, ExtensionAppList* apps);
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
index bfd3cdd..2354c83 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
+++ b/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
@@ -32,10 +32,10 @@ const char kPackagedApp2Id[] = "jlklkagmeajbjiobondfhiekepofmljl";
// Get a string of all apps in |model| joined with ','.
std::string GetModelContent(app_list::AppListModel* model) {
std::string content;
- for (size_t i = 0; i < model->apps()->item_count(); ++i) {
+ for (size_t i = 0; i < model->item_list()->item_count(); ++i) {
if (i > 0)
content += ',';
- content += model->apps()->GetItemAt(i)->title();
+ content += model->item_list()->item_at(i)->title();
}
return content;
}
@@ -285,15 +285,15 @@ TEST_F(ExtensionAppModelBuilderTest, OrdinalConfilicts) {
TEST_F(ExtensionAppModelBuilderTest, SwitchProfile) {
ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
- EXPECT_EQ(kDefaultAppCount, model_->apps()->item_count());
+ EXPECT_EQ(kDefaultAppCount, model_->item_list()->item_count());
// Switch to a profile with no apps, ensure all apps are removed.
TestingProfile::Builder profile_builder;
scoped_ptr<TestingProfile> profile2(profile_builder.Build());
builder.SwitchProfile(profile2.get());
- EXPECT_EQ(0u, model_->apps()->item_count());
+ EXPECT_EQ(0u, model_->item_list()->item_count());
// Switch back to the main profile, ensure apps are restored.
builder.SwitchProfile(profile_.get());
- EXPECT_EQ(kDefaultAppCount, model_->apps()->item_count());
+ EXPECT_EQ(kDefaultAppCount, model_->item_list()->item_count());
}
diff --git a/chrome/browser/ui/app_list/fast_show_pickler.cc b/chrome/browser/ui/app_list/fast_show_pickler.cc
index 80b2c0f..0119b03 100644
--- a/chrome/browser/ui/app_list/fast_show_pickler.cc
+++ b/chrome/browser/ui/app_list/fast_show_pickler.cc
@@ -207,23 +207,23 @@ scoped_ptr<Pickle> FastShowPickler::PickleAppListModelForFastShow(
return scoped_ptr<Pickle>();
if (!result->WriteBool(model->signed_in()))
return scoped_ptr<Pickle>();
- if (!result->WriteInt((int) model->apps()->item_count()))
+ if (!result->WriteInt((int) model->item_list()->item_count()))
return scoped_ptr<Pickle>();
- for (size_t i = 0; i < model->apps()->item_count(); ++i) {
- if (!PickleAppListItemModel(result.get(), model->apps()->GetItemAt(i)))
+ for (size_t i = 0; i < model->item_list()->item_count(); ++i) {
+ if (!PickleAppListItemModel(result.get(), model->item_list()->item_at(i)))
return scoped_ptr<Pickle>();
}
return result.Pass();
}
void FastShowPickler::CopyOver(AppListModel* src, AppListModel* dest) {
- dest->apps()->DeleteAll();
+ dest->item_list()->DeleteItemsByType(NULL /* all items */);
dest->SetSignedIn(src->signed_in());
- for (size_t i = 0; i < src->apps()->item_count(); i++) {
- AppListItemModel* src_item = src->apps()->GetItemAt(i);
+ for (size_t i = 0; i < src->item_list()->item_count(); i++) {
+ AppListItemModel* src_item = src->item_list()->item_at(i);
AppListItemModel* dest_item = new AppListItemModel(src_item->id());
CopyOverItem(src_item, dest_item);
- dest->apps()->Add(dest_item);
+ dest->item_list()->AddItem(dest_item);
}
}
@@ -248,7 +248,7 @@ FastShowPickler::UnpickleAppListModelForFastShow(Pickle* pickle) {
scoped_ptr<AppListItemModel> item(UnpickleAppListItemModel(&it).Pass());
if (!item)
return scoped_ptr<AppListModel>();
- model->apps()->Add(item.release());
+ model->item_list()->AddItem(item.release());
}
return model.Pass();
diff --git a/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc b/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc
index e87fe89..580c3a5 100644
--- a/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc
+++ b/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc
@@ -17,17 +17,17 @@ using app_list::AppListModel;
class AppListModelPicklerUnitTest : public testing::Test {
protected:
void CheckIsSame(AppListModel* m1, AppListModel* m2) {
- ASSERT_EQ(m1->apps()->item_count(), m2->apps()->item_count());
+ ASSERT_EQ(m1->item_list()->item_count(), m2->item_list()->item_count());
ASSERT_EQ(m1->signed_in(), m2->signed_in());
- for (size_t i = 0; i < m1->apps()->item_count(); i++) {
- ASSERT_EQ(m1->apps()->GetItemAt(i)->id(),
- m2->apps()->GetItemAt(i)->id());
- ASSERT_EQ(m1->apps()->GetItemAt(i)->title(),
- m2->apps()->GetItemAt(i)->title());
- ASSERT_EQ(m1->apps()->GetItemAt(i)->full_name(),
- m2->apps()->GetItemAt(i)->full_name());
- CompareImages(m1->apps()->GetItemAt(i)->icon(),
- m2->apps()->GetItemAt(i)->icon());
+ for (size_t i = 0; i < m1->item_list()->item_count(); i++) {
+ ASSERT_EQ(m1->item_list()->item_at(i)->id(),
+ m2->item_list()->item_at(i)->id());
+ ASSERT_EQ(m1->item_list()->item_at(i)->title(),
+ m2->item_list()->item_at(i)->title());
+ ASSERT_EQ(m1->item_list()->item_at(i)->full_name(),
+ m2->item_list()->item_at(i)->full_name());
+ CompareImages(m1->item_list()->item_at(i)->icon(),
+ m2->item_list()->item_at(i)->icon());
}
}
@@ -79,7 +79,7 @@ TEST_F(AppListModelPicklerUnitTest, OneItem) {
AppListModel model;
AppListItemModel* app1 = new AppListItemModel("abc");
app1->SetTitleAndFullName("ht", "hello, there");
- model.apps()->Add(app1);
+ model.item_list()->AddItem(app1);
DoConsistencyChecks(&model);
}
@@ -88,11 +88,11 @@ TEST_F(AppListModelPicklerUnitTest, TwoItems) {
AppListModel model;
AppListItemModel* app1 = new AppListItemModel("abc");
app1->SetTitleAndFullName("ht", "hello, there");
- model.apps()->Add(app1);
+ model.item_list()->AddItem(app1);
AppListItemModel* app2 = new AppListItemModel("abc2");
app2->SetTitleAndFullName("ht2", "hello, there 2");
- model.apps()->Add(app2);
+ model.item_list()->AddItem(app2);
DoConsistencyChecks(&model);
}
@@ -102,11 +102,11 @@ TEST_F(AppListModelPicklerUnitTest, Images) {
AppListItemModel* app1 = new AppListItemModel("abc");
app1->SetTitleAndFullName("ht", "hello, there");
app1->SetIcon(MakeImage(), true);
- model.apps()->Add(app1);
+ model.item_list()->AddItem(app1);
AppListItemModel* app2 = new AppListItemModel("abc2");
app2->SetTitleAndFullName("ht2", "hello, there 2");
- model.apps()->Add(app2);
+ model.item_list()->AddItem(app2);
DoConsistencyChecks(&model);
}
@@ -116,7 +116,7 @@ TEST_F(AppListModelPicklerUnitTest, EmptyImage) {
AppListItemModel* app1 = new AppListItemModel("abc");
app1->SetTitleAndFullName("ht", "hello, there");
app1->SetIcon(gfx::ImageSkia(), true);
- model.apps()->Add(app1);
+ model.item_list()->AddItem(app1);
DoConsistencyChecks(&model);
}
diff --git a/ui/app_list/DEPS b/ui/app_list/DEPS
index bfb1162..bd3bf14 100644
--- a/ui/app_list/DEPS
+++ b/ui/app_list/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+grit/ui_resources.h",
"+grit/ui_strings.h",
"+skia",
+ "+sync",
"+third_party/skia",
# Allow inclusion of third-party code:
"+third_party/GTM", # Google Toolbox for Mac.
diff --git a/ui/app_list/app_list.gyp b/ui/app_list/app_list.gyp
index 90864a7..15bd6e1 100644
--- a/ui/app_list/app_list.gyp
+++ b/ui/app_list/app_list.gyp
@@ -31,6 +31,9 @@
'app_list_export.h',
'app_list_folder_item.cc',
'app_list_folder_item.h',
+ 'app_list_item_list.cc',
+ 'app_list_item_list.h',
+ 'app_list_item_list_observer.h',
'app_list_item_model.cc',
'app_list_item_model.h',
'app_list_item_model_observer.h',
diff --git a/ui/app_list/app_list_folder_item.cc b/ui/app_list/app_list_folder_item.cc
index 95e5530..e7c505a 100644
--- a/ui/app_list/app_list_folder_item.cc
+++ b/ui/app_list/app_list_folder_item.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "ui/app_list/app_list_folder_item.h"
+
+#include "ui/app_list/app_list_item_list.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/canvas_image_source.h"
#include "ui/gfx/image/image_skia_operations.h"
@@ -91,38 +93,14 @@ class FolderImageSource : public gfx::CanvasImageSource {
AppListFolderItem::AppListFolderItem(const std::string& id)
: AppListItemModel(id),
- apps_(new Apps) {
+ item_list_(new AppListItemList) {
+ item_list_->AddObserver(this);
}
AppListFolderItem::~AppListFolderItem() {
for (size_t i = 0; i < top_items_.size(); ++i)
top_items_[i]->RemoveObserver(this);
-}
-
-void AppListFolderItem::AddItem(AppListItemModel* item) {
- 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())
- break;
- }
- apps_->AddAt(index, item);
- if (index <= kNumTopApps)
- UpdateTopItems();
-}
-
-void AppListFolderItem::DeleteItem(const std::string& id) {
- for (size_t i = 0; i < apps_->item_count(); ++i) {
- AppListItemModel* item = apps_->GetItemAt(i);
- if (item->id() == id) {
- scoped_ptr<AppListItemModel> to_be_deleted(apps_->RemoveAt(i));
- DCHECK(item == to_be_deleted.get());
- if (i <= kNumTopApps)
- UpdateTopItems();
- return;
- }
- }
+ item_list_->RemoveObserver(this);
}
void AppListFolderItem::UpdateIcon() {
@@ -137,12 +115,6 @@ void AppListFolderItem::UpdateIcon() {
SetIcon(icon, false);
}
-std::string AppListFolderItem::GetSortOrder() const {
- // For now, put folders at the end of the list.
- // TODO(stevenjb): Implement synced app list ordering.
- return "zzzzzzzz";
-}
-
void AppListFolderItem::Activate(int event_flags) {
// Folder handling is implemented by the View, so do nothing.
}
@@ -175,13 +147,33 @@ void AppListFolderItem::ItemIsInstallingChanged() {
void AppListFolderItem::ItemPercentDownloadedChanged() {
}
+void AppListFolderItem::OnListItemAdded(size_t index,
+ AppListItemModel* item) {
+ if (index <= kNumTopApps)
+ UpdateTopItems();
+}
+
+void AppListFolderItem::OnListItemRemoved(size_t index,
+ AppListItemModel* item) {
+ if (index <= kNumTopApps)
+ UpdateTopItems();
+}
+
+void AppListFolderItem::OnListItemMoved(size_t from_index,
+ size_t to_index,
+ AppListItemModel* item) {
+ if (from_index <= kNumTopApps || to_index <= kNumTopApps)
+ UpdateTopItems();
+}
+
void AppListFolderItem::UpdateTopItems() {
for (size_t i = 0; i < top_items_.size(); ++i)
top_items_[i]->RemoveObserver(this);
top_items_.clear();
- for (size_t i = 0; i < kNumTopApps && i < apps_->item_count(); ++i) {
- AppListItemModel* item = apps_->GetItemAt(i);
+ for (size_t i = 0;
+ i < kNumTopApps && i < item_list_->item_count(); ++i) {
+ AppListItemModel* item = item_list_->item_at(i);
item->AddObserver(this);
top_items_.push_back(item);
}
diff --git a/ui/app_list/app_list_folder_item.h b/ui/app_list/app_list_folder_item.h
index db078ea..dd2ce7b 100644
--- a/ui/app_list/app_list_folder_item.h
+++ b/ui/app_list/app_list_folder_item.h
@@ -6,55 +6,56 @@
#define UI_APP_LIST_APP_LIST_FOLDER_ITEM_H_
#include "ui/app_list/app_list_export.h"
+#include "ui/app_list/app_list_item_list_observer.h"
#include "ui/app_list/app_list_item_model.h"
#include "ui/app_list/app_list_item_model_observer.h"
#include "ui/base/models/list_model.h"
namespace app_list {
+class AppListItemList;
+
// AppListFolderItem implements the model/controller for folders.
class APP_LIST_EXPORT AppListFolderItem : public AppListItemModel,
+ public AppListItemListObserver,
public AppListItemModelObserver {
public:
- typedef ui::ListModel<AppListItemModel> Apps;
-
explicit AppListFolderItem(const std::string& id);
virtual ~AppListFolderItem();
- // Adds |item| to |apps_|. Takes ownership of |item|.
- void AddItem(AppListItemModel* item);
-
- // Finds |item| in |apps_| and deletes it.
- void DeleteItem(const std::string& id);
-
// Updates the folder's icon.
void UpdateIcon();
- Apps* apps() { return apps_.get(); }
+ AppListItemList* item_list() { return item_list_.get(); }
+
+ static const char kAppType[];
+ private:
// AppListItemModel
- virtual std::string GetSortOrder() const OVERRIDE;
virtual void Activate(int event_flags) OVERRIDE;
virtual const char* GetAppType() const OVERRIDE;
virtual ui::MenuModel* GetContextMenuModel() OVERRIDE;
- // AppListItemModelObserver overrides:
+ // AppListItemModelObserver
virtual void ItemIconChanged() OVERRIDE;
virtual void ItemTitleChanged() OVERRIDE;
virtual void ItemHighlightedChanged() OVERRIDE;
virtual void ItemIsInstallingChanged() OVERRIDE;
virtual void ItemPercentDownloadedChanged() OVERRIDE;
- static const char kAppType[];
-
- private:
- typedef std::vector<AppListItemModel*> AppListItemList;
+ // AppListItemListObserver
+ virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE;
+ virtual void OnListItemRemoved(size_t index,
+ AppListItemModel* item) OVERRIDE;;
+ virtual void OnListItemMoved(size_t from_index,
+ size_t to_index,
+ AppListItemModel* item) OVERRIDE;
void UpdateTopItems();
- scoped_ptr<Apps> apps_;
+ scoped_ptr<AppListItemList> item_list_;
// Top items for generating folder icon.
- AppListItemList top_items_;
+ std::vector<AppListItemModel*> top_items_;
DISALLOW_COPY_AND_ASSIGN(AppListFolderItem);
};
diff --git a/ui/app_list/app_list_item_list.cc b/ui/app_list/app_list_item_list.cc
new file mode 100644
index 0000000..29578f2
--- /dev/null
+++ b/ui/app_list/app_list_item_list.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/app_list/app_list_item_list.h"
+
+#include "ui/app_list/app_list_item_model.h"
+
+namespace app_list {
+
+AppListItemList::AppListItemList() {
+}
+
+AppListItemList::~AppListItemList() {
+}
+
+void AppListItemList::AddObserver(AppListItemListObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void AppListItemList::RemoveObserver(AppListItemListObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+AppListItemModel* AppListItemList::FindItem(const std::string& id) {
+ for (size_t i = 0; i < app_list_items_.size(); ++i) {
+ AppListItemModel* item = app_list_items_[i];
+ if (item->id() == id)
+ return item;
+ }
+ return NULL;
+}
+
+size_t AppListItemList::AddItem(AppListItemModel* item) {
+ size_t index = GetItemSortOrderIndex(item);
+ app_list_items_.insert(app_list_items_.begin() + index, item);
+ FOR_EACH_OBSERVER(AppListItemListObserver,
+ observers_,
+ OnListItemAdded(index, item));
+ return index;
+}
+
+void AppListItemList::DeleteItem(const std::string& id) {
+ for (size_t i = 0; i < app_list_items_.size(); ++i) {
+ AppListItemModel* item = app_list_items_[i];
+ if (item->id() == id) {
+ DeleteItemAt(i);
+ break;
+ }
+ }
+}
+
+void AppListItemList::DeleteItemsByType(const char* type) {
+ for (int i = static_cast<int>(app_list_items_.size()) - 1;
+ i >= 0; --i) {
+ AppListItemModel* item = app_list_items_[i];
+ if (!type || item->GetAppType() == type)
+ DeleteItemAt(i);
+ }
+}
+
+void AppListItemList::MoveItem(size_t from_index, size_t to_index) {
+ DCHECK_LT(from_index, item_count());
+ DCHECK_LT(to_index, item_count());
+ if (from_index == to_index)
+ return;
+
+ AppListItemModel* target_item = app_list_items_[from_index];
+ app_list_items_.weak_erase(app_list_items_.begin() + from_index);
+ app_list_items_.insert(app_list_items_.begin() + to_index, target_item);
+
+ // Update position
+ AppListItemModel* prev = to_index > 0 ? app_list_items_[to_index - 1] : NULL;
+ AppListItemModel* next = to_index < app_list_items_.size() - 1 ?
+ app_list_items_[to_index + 1] : NULL;
+ CHECK_NE(prev, next);
+
+ // It is possible that items were added with the same ordinal. Rather than
+ // resolving a potentially complicated chain of conflicts, just set the
+ // ordinal before |next| (which will place it before both items).
+ if (prev && next && prev->position().Equals(next->position()))
+ prev = NULL;
+
+ VLOG(2) << "Move: " << target_item->position().ToDebugString()
+ << " Prev: " << (prev ? prev->position().ToDebugString() : "(none)")
+ << " Next: " << (next ? next->position().ToDebugString() : "(none)");
+ if (!prev)
+ target_item->set_position(next->position().CreateBefore());
+ else if (!next)
+ target_item->set_position(prev->position().CreateAfter());
+ else
+ target_item->set_position(prev->position().CreateBetween(next->position()));
+ FOR_EACH_OBSERVER(AppListItemListObserver,
+ observers_,
+ OnListItemMoved(from_index, to_index, target_item));
+}
+
+// AppListItemList private
+
+void AppListItemList::DeleteItemAt(size_t index) {
+ DCHECK_LT(index, item_count());
+ AppListItemModel* item = app_list_items_[index];
+ app_list_items_.weak_erase(app_list_items_.begin() + index);
+ FOR_EACH_OBSERVER(AppListItemListObserver,
+ observers_,
+ OnListItemRemoved(index, item));
+ delete item;
+}
+
+size_t AppListItemList::GetItemSortOrderIndex(AppListItemModel* item) {
+ syncer::StringOrdinal position = item->position();
+ if (!position.IsValid()) {
+ size_t nitems = app_list_items_.size();
+ if (nitems == 0) {
+ position = syncer::StringOrdinal::CreateInitialOrdinal();
+ } else {
+ position = app_list_items_[nitems - 1]->position().CreateAfter();
+ }
+ item->set_position(position);
+ return nitems;
+ }
+ // Note: app_list_items_ is sorted by convention, but sorting is not enforced
+ // (items' positions might be changed outside this class).
+ size_t index = 0;
+ for (; index < app_list_items_.size(); ++index) {
+ if (position.LessThan(app_list_items_[index]->position()))
+ break;
+ }
+ return index;
+}
+
+} // namespace app_list
diff --git a/ui/app_list/app_list_item_list.h b/ui/app_list/app_list_item_list.h
new file mode 100644
index 0000000..6b033c9
--- /dev/null
+++ b/ui/app_list/app_list_item_list.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_APP_LIST_APP_LIST_ITEM_LIST_H_
+#define UI_APP_LIST_APP_LIST_ITEM_LIST_H_
+
+#include <string>
+
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
+#include "ui/app_list/app_list_export.h"
+#include "ui/app_list/app_list_item_list_observer.h"
+
+namespace app_list {
+
+class AppListItemModel;
+
+// Class to manage items in the app list. Used both by AppListModel and
+// AppListFolderItem. Manages the position ordinal of items in the list, and
+// notifies observers when items in the list are added / deleted / moved.
+class APP_LIST_EXPORT AppListItemList {
+ public:
+ AppListItemList();
+ virtual ~AppListItemList();
+
+ void AddObserver(AppListItemListObserver* observer);
+ void RemoveObserver(AppListItemListObserver* observer);
+
+ // Find item matching |id|. NOTE: Requires a linear search.
+ AppListItemModel* FindItem(const std::string& id);
+
+ // Adds |item| to the end of |app_list_items_|. Takes ownership of |item|.
+ // Triggers observers_.OnListItemAdded(). Returns the index of the added item.
+ size_t AddItem(AppListItemModel* item);
+
+ // Finds item matching |id| in |app_list_items_| (linear search) and deletes
+ // it. Triggers observers_.OnListItemRemoved() after removing the item from
+ // the list and before deleting it.
+ void DeleteItem(const std::string& id);
+
+ // Deletes all items matching |type| which must be a statically defined
+ // type descriptor, e.g. AppListFolderItem::kAppType. If |type| is NULL,
+ // deletes all items. Triggers observers_.OnListItemRemoved() for each item
+ // as for DeleteItem.
+ void DeleteItemsByType(const char* type);
+
+ // Moves item at |from_index| to |to_index|.
+ // Triggers observers_.OnListItemMoved().
+ void MoveItem(size_t from_index, size_t to_index);
+
+ AppListItemModel* item_at(size_t index) { return app_list_items_[index]; }
+ size_t item_count() const { return app_list_items_.size(); }
+
+ private:
+ // Deletes item at |index| and signals observers.
+ void DeleteItemAt(size_t index);
+
+ // Returns the index at which to insert |item| in |app_list_items_| based on
+ // |item|->position(). If |item|->position() is not valid, returns
+ // |app_list_items_|.item_count() and sets |item|->position() appropriately.
+ size_t GetItemSortOrderIndex(AppListItemModel* item);
+
+ ScopedVector<AppListItemModel> app_list_items_;
+ ObserverList<AppListItemListObserver> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppListItemList);
+};
+
+} // namespace app_list
+
+#endif // UI_APP_LIST_APP_LIST_ITEM_LIST_H_
diff --git a/ui/app_list/app_list_item_list_observer.h b/ui/app_list/app_list_item_list_observer.h
new file mode 100644
index 0000000..bca7e90
--- /dev/null
+++ b/ui/app_list/app_list_item_list_observer.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_APP_LIST_APP_LIST_ITEM_LIST_OBSERVER_H_
+#define UI_APP_LIST_APP_LIST_ITEM_LIST_OBSERVER_H_
+
+#include "base/basictypes.h"
+
+namespace app_list {
+
+class AppListItemModel;
+
+class APP_LIST_EXPORT AppListItemListObserver {
+ public:
+ // Triggered after |item| has been added to the list at |index|.
+ virtual void OnListItemAdded(size_t index, AppListItemModel* item) {}
+
+ // Triggered after an item has been removed from the list at |index|, just
+ // before the item is deleted.
+ virtual void OnListItemRemoved(size_t index, AppListItemModel* item) {}
+
+ // Triggered after |item| has been moved from |from_index| to |to_index|.
+ virtual void OnListItemMoved(size_t from_index,
+ size_t to_index,
+ AppListItemModel* item) {}
+
+ protected:
+ virtual ~AppListItemListObserver() {}
+};
+
+} // namespace app_list
+
+#endif // UI_APP_LIST_APP_LIST_ITEM_LIST_OBSERVER_H_
diff --git a/ui/app_list/app_list_item_model.cc b/ui/app_list/app_list_item_model.cc
index 87b6969..1846f5e 100644
--- a/ui/app_list/app_list_item_model.cc
+++ b/ui/app_list/app_list_item_model.cc
@@ -73,10 +73,6 @@ void AppListItemModel::RemoveObserver(AppListItemModelObserver* observer) {
observers_.RemoveObserver(observer);
}
-std::string AppListItemModel::GetSortOrder() const {
- return "";
-}
-
void AppListItemModel::Activate(int event_flags) {
}
diff --git a/ui/app_list/app_list_item_model.h b/ui/app_list/app_list_item_model.h
index 859b348..505bbb6 100644
--- a/ui/app_list/app_list_item_model.h
+++ b/ui/app_list/app_list_item_model.h
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "base/observer_list.h"
+#include "sync/api/string_ordinal.h"
#include "ui/app_list/app_list_export.h"
#include "ui/gfx/image/image_skia.h"
@@ -46,14 +47,15 @@ class APP_LIST_EXPORT AppListItemModel {
int percent_downloaded() const { return percent_downloaded_; }
const std::string& id() const { return id_; }
+ const syncer::StringOrdinal& position() const { return position_; }
+ void set_position(const syncer::StringOrdinal& new_position) {
+ DCHECK(new_position.IsValid());
+ position_ = new_position;
+ }
void AddObserver(AppListItemModelObserver* observer);
void RemoveObserver(AppListItemModelObserver* observer);
- // Returns a string used for initially sorting the apps (used by
- // AppListModel::AddItem). Defaults to an empty string.
- virtual std::string GetSortOrder() const;
-
// Activates (opens) the item. Does nothing by default.
virtual void Activate(int event_flags);
@@ -67,7 +69,10 @@ class APP_LIST_EXPORT AppListItemModel {
virtual ui::MenuModel* GetContextMenuModel();
private:
+ friend class AppListModelTest;
+
const std::string id_;
+ syncer::StringOrdinal position_;
gfx::ImageSkia icon_;
bool has_shadow_;
std::string title_;
diff --git a/ui/app_list/app_list_model.cc b/ui/app_list/app_list_model.cc
index 2464656..40bb8e9 100644
--- a/ui/app_list/app_list_model.cc
+++ b/ui/app_list/app_list_model.cc
@@ -16,7 +16,7 @@ AppListModel::User::User() : active(false) {}
AppListModel::User::~User() {}
AppListModel::AppListModel()
- : apps_(new Apps),
+ : item_list_(new AppListItemList),
search_box_(new SearchBoxModel),
results_(new SearchResults),
signed_in_(false),
@@ -61,34 +61,4 @@ void AppListModel::SetSignedIn(bool signed_in) {
OnAppListModelSigninStatusChanged());
}
-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;
- }
- return NULL;
-}
-
-void AppListModel::AddItem(AppListItemModel* item) {
- 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())
- break;
- }
- apps_->AddAt(index, item);
-}
-
-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;
- }
- }
-}
-
} // namespace app_list
diff --git a/ui/app_list/app_list_model.h b/ui/app_list/app_list_model.h
index 2238941..fbc7970 100644
--- a/ui/app_list/app_list_model.h
+++ b/ui/app_list/app_list_model.h
@@ -13,18 +13,20 @@
#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "ui/app_list/app_list_export.h"
+#include "ui/app_list/app_list_item_list.h"
#include "ui/base/models/list_model.h"
namespace app_list {
+class AppListItemList;
class AppListItemModel;
class AppListModelObserver;
class SearchBoxModel;
class SearchResult;
-// Master model of app list that consists of three sub models: Apps,
-// SearchBoxModel and SearchResults. The Apps sub model owns a list of
-// AppListItemModel and is displayed in the grid view. SearchBoxModel is
+// Master model of app list that consists of three sub models: AppListItemList,
+// SearchBoxModel and SearchResults. The AppListItemList sub model owns a list
+// of AppListItemModel and is displayed in the grid view. SearchBoxModel is
// the model for SearchBoxView. SearchResults owns a list of SearchResult.
class APP_LIST_EXPORT AppListModel {
public:
@@ -51,7 +53,6 @@ class APP_LIST_EXPORT AppListModel {
STATUS_SYNCING, // Syncing apps or installing synced apps.
};
- typedef ui::ListModel<AppListItemModel> Apps;
typedef ui::ListModel<SearchResult> SearchResults;
typedef std::vector<User> Users;
@@ -65,18 +66,7 @@ class APP_LIST_EXPORT AppListModel {
void SetUsers(const Users& profile_menu_items);
void SetSignedIn(bool signed_in);
- // Find item matching |id|. NOTE: Requires a linear search.
- AppListItemModel* FindItem(const std::string& id);
-
- // Adds |item| to |apps_|. Takes ownership of |item|. Uses item->SortOrder()
- // to insert in the correct place. TODO(stevenjb): Use synced app list order
- // instead of SortOrder when available: crbug.com/305024.
- void AddItem(AppListItemModel* item);
-
- // Finds |item| in |apps_| and deletes it.
- void DeleteItem(const std::string& id);
-
- Apps* apps() { return apps_.get(); }
+ AppListItemList* item_list() { return item_list_.get(); }
SearchBoxModel* search_box() { return search_box_.get(); }
SearchResults* results() { return results_.get(); }
Status status() const { return status_; }
@@ -87,8 +77,7 @@ class APP_LIST_EXPORT AppListModel {
}
private:
- scoped_ptr<Apps> apps_;
-
+ scoped_ptr<AppListItemList> item_list_;
scoped_ptr<SearchBoxModel> search_box_;
scoped_ptr<SearchResults> results_;
diff --git a/ui/app_list/app_list_model_unittest.cc b/ui/app_list/app_list_model_unittest.cc
index 02d77a4..01df3e2 100644
--- a/ui/app_list/app_list_model_unittest.cc
+++ b/ui/app_list/app_list_model_unittest.cc
@@ -8,6 +8,7 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/app_list/app_list_folder_item.h"
#include "ui/app_list/app_list_item_model.h"
#include "ui/app_list/app_list_model_observer.h"
#include "ui/app_list/test/app_list_test_model.h"
@@ -18,7 +19,7 @@ namespace app_list {
namespace {
class TestObserver : public AppListModelObserver,
- public ui::ListModelObserver {
+ public AppListItemListObserver {
public:
TestObserver()
: status_changed_count_(0),
@@ -44,22 +45,22 @@ class TestObserver : public AppListModelObserver,
++signin_changed_count_;
}
- // ui::ListModelObserver
- virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE {
- items_added_ += count;
+ // AppListItemListObserver
+ virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE {
+ items_added_++;
}
- virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE {
- items_removed_ += count;
+ virtual void OnListItemRemoved(size_t index,
+ AppListItemModel* item) OVERRIDE {
+ items_removed_++;
}
- virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE {
+ virtual void OnListItemMoved(size_t from_index,
+ size_t to_index,
+ AppListItemModel* item) OVERRIDE {
items_moved_++;
}
- virtual void ListItemsChanged(size_t index, size_t target_index) OVERRIDE {
- }
-
int status_changed_count() const { return status_changed_count_; }
int users_changed_count() const { return users_changed_count_; }
int signin_changed_count() const { return signin_changed_count_; }
@@ -67,6 +68,15 @@ class TestObserver : public AppListModelObserver,
size_t items_removed() { return items_removed_; }
size_t items_moved() { return items_moved_; }
+ void ResetCounts() {
+ status_changed_count_ = 0;
+ users_changed_count_ = 0;
+ signin_changed_count_ = 0;
+ items_added_ = 0;
+ items_removed_ = 0;
+ items_moved_ = 0;
+ }
+
private:
int status_changed_count_;
int users_changed_count_;
@@ -88,14 +98,19 @@ class AppListModelTest : public testing::Test {
// testing::Test overrides:
virtual void SetUp() OVERRIDE {
model_.AddObserver(&observer_);
- model_.apps()->AddObserver(&observer_);
+ model_.item_list()->AddObserver(&observer_);
}
virtual void TearDown() OVERRIDE {
model_.RemoveObserver(&observer_);
- model_.apps()->RemoveObserver(&observer_);
+ model_.item_list()->RemoveObserver(&observer_);
}
protected:
+ bool ItemObservedByFolder(AppListFolderItem* folder,
+ AppListItemModel* item) {
+ return item->observers_.HasObserver(folder);
+ }
+
test::AppListTestModel model_;
TestObserver observer_;
@@ -148,10 +163,10 @@ TEST_F(AppListModelTest, AppsObserver) {
TEST_F(AppListModelTest, ModelGetItem) {
const size_t num_apps = 2;
model_.PopulateApps(num_apps);
- AppListItemModel* item0 = model_.apps()->GetItemAt(0);
+ AppListItemModel* item0 = model_.item_list()->item_at(0);
ASSERT_TRUE(item0);
EXPECT_EQ(model_.GetItemName(0), item0->id());
- AppListItemModel* item1 = model_.apps()->GetItemAt(1);
+ AppListItemModel* item1 = model_.item_list()->item_at(1);
ASSERT_TRUE(item1);
EXPECT_EQ(model_.GetItemName(1), item1->id());
}
@@ -160,26 +175,137 @@ TEST_F(AppListModelTest, ModelFindItem) {
const size_t num_apps = 2;
model_.PopulateApps(num_apps);
std::string item_name0 = model_.GetItemName(0);
- AppListItemModel* item0 = model_.FindItem(item_name0);
+ AppListItemModel* item0 = model_.item_list()->FindItem(item_name0);
ASSERT_TRUE(item0);
EXPECT_EQ(item_name0, item0->id());
std::string item_name1 = model_.GetItemName(1);
- AppListItemModel* item1 = model_.FindItem(item_name1);
+ AppListItemModel* item1 = model_.item_list()->FindItem(item_name1);
ASSERT_TRUE(item1);
EXPECT_EQ(item_name1, item1->id());
}
+TEST_F(AppListModelTest, ModelAddItem) {
+ const size_t num_apps = 2;
+ model_.PopulateApps(num_apps);
+ // Adding another item will add it to the end.
+ model_.CreateAndAddItem("Added Item 1");
+ ASSERT_EQ(num_apps + 1, model_.item_list()->item_count());
+ EXPECT_EQ("Added Item 1", model_.item_list()->item_at(num_apps)->id());
+ // Add an item between items 0 and 1.
+ app_list::AppListItemModel* item0 = model_.item_list()->item_at(0);
+ ASSERT_TRUE(item0);
+ app_list::AppListItemModel* item1 = model_.item_list()->item_at(1);
+ ASSERT_TRUE(item1);
+ app_list::AppListItemModel* item2 =
+ model_.CreateItem("Added Item 2", "Added Item 2");
+ item2->set_position(item0->position().CreateBetween(item1->position()));
+ model_.item_list()->AddItem(item2);
+ EXPECT_EQ(num_apps + 2, model_.item_list()->item_count());
+ EXPECT_EQ("Added Item 2", model_.item_list()->item_at(1)->id());
+}
+
TEST_F(AppListModelTest, ModelMoveItem) {
const size_t num_apps = 3;
model_.PopulateApps(num_apps);
// Adding another item will add it to the end.
model_.CreateAndAddItem("Inserted Item");
- ASSERT_EQ(num_apps + 1, model_.apps()->item_count());
+ ASSERT_EQ(num_apps + 1, model_.item_list()->item_count());
// Move it to the position 1.
- model_.apps()->Move(num_apps, 1);
- AppListItemModel* item = model_.apps()->GetItemAt(1);
+ model_.item_list()->MoveItem(num_apps, 1);
+ AppListItemModel* item = model_.item_list()->item_at(1);
ASSERT_TRUE(item);
EXPECT_EQ("Inserted Item", item->id());
}
+TEST_F(AppListModelTest, ModelRemoveItem) {
+ const size_t num_apps = 4;
+ model_.PopulateApps(num_apps);
+ // Remove an item in the middle.
+ model_.item_list()->DeleteItem(model_.GetItemName(1));
+ EXPECT_EQ(num_apps - 1, model_.item_list()->item_count());
+ EXPECT_EQ(1u, observer_.items_removed());
+ // Remove the first item in the list.
+ model_.item_list()->DeleteItem(model_.GetItemName(0));
+ EXPECT_EQ(num_apps - 2, model_.item_list()->item_count());
+ EXPECT_EQ(2u, observer_.items_removed());
+ // Remove the last item in the list.
+ model_.item_list()->DeleteItem(model_.GetItemName(num_apps - 1));
+ EXPECT_EQ(num_apps - 3, model_.item_list()->item_count());
+ EXPECT_EQ(3u, observer_.items_removed());
+ // Ensure that the first item is the expected one
+ AppListItemModel* item0 = model_.item_list()->item_at(0);
+ ASSERT_TRUE(item0);
+ EXPECT_EQ(model_.GetItemName(2), item0->id());
+}
+
+TEST_F(AppListModelTest, ModelRemoveItemByType) {
+ const size_t num_apps = 4;
+ model_.PopulateApps(num_apps);
+ model_.item_list()->AddItem(new AppListFolderItem("folder1"));
+ model_.item_list()->AddItem(new AppListFolderItem("folder2"));
+ model_.item_list()->DeleteItemsByType(test::AppListTestModel::kAppType);
+ EXPECT_EQ(num_apps, observer_.items_removed());
+ EXPECT_EQ(2u, model_.item_list()->item_count());
+ model_.item_list()->DeleteItemsByType(AppListFolderItem::kAppType);
+ EXPECT_EQ(num_apps + 2, observer_.items_removed());
+ EXPECT_EQ(0u, model_.item_list()->item_count());
+ // Delete all items
+ observer_.ResetCounts();
+ model_.PopulateApps(num_apps);
+ model_.item_list()->AddItem(new AppListFolderItem("folder1"));
+ model_.item_list()->AddItem(new AppListFolderItem("folder2"));
+ model_.item_list()->DeleteItemsByType(NULL /* all items */);
+ EXPECT_EQ(num_apps + 2, observer_.items_removed());
+ EXPECT_EQ(0u, model_.item_list()->item_count());
+}
+
+TEST_F(AppListModelTest, AppOrder) {
+ const size_t num_apps = 5;
+ model_.PopulateApps(num_apps);
+ // Ensure order is preserved.
+ for (size_t i = 1; i < num_apps; ++i) {
+ EXPECT_TRUE(model_.item_list()->item_at(i)->position().GreaterThan(
+ model_.item_list()->item_at(i - 1)->position()));
+ }
+ // Move an app
+ model_.item_list()->MoveItem(num_apps - 1, 1);
+ // Ensure order is preserved.
+ for (size_t i = 1; i < num_apps; ++i) {
+ EXPECT_TRUE(model_.item_list()->item_at(i)->position().GreaterThan(
+ model_.item_list()->item_at(i - 1)->position()));
+ }
+}
+
+TEST_F(AppListModelTest, FolderItem) {
+ AppListFolderItem* folder = new AppListFolderItem("folder1");
+ const size_t num_folder_apps = 8;
+ const size_t num_observed_apps = 4;
+ for (int i = 0; static_cast<size_t>(i) < num_folder_apps; ++i) {
+ std::string name = model_.GetItemName(i);
+ folder->item_list()->AddItem(model_.CreateItem(name, name));
+ }
+ // Check that items 0 and 3 are observed.
+ EXPECT_TRUE(ItemObservedByFolder(folder, folder->item_list()->item_at(0)));
+ EXPECT_TRUE(ItemObservedByFolder(
+ folder, folder->item_list()->item_at(num_observed_apps - 1)));
+ // Check that item 4 is not observed.
+ EXPECT_FALSE(ItemObservedByFolder(
+ folder, folder->item_list()->item_at(num_observed_apps)));
+ folder->item_list()->MoveItem(num_observed_apps, 0);
+ // Confirm that everything was moved where expected.
+ EXPECT_EQ(model_.GetItemName(num_observed_apps),
+ folder->item_list()->item_at(0)->id());
+ EXPECT_EQ(model_.GetItemName(0),
+ folder->item_list()->item_at(1)->id());
+ EXPECT_EQ(model_.GetItemName(num_observed_apps - 1),
+ folder->item_list()->item_at(num_observed_apps)->id());
+ // Check that items 0 and 3 are observed.
+ EXPECT_TRUE(ItemObservedByFolder(folder, folder->item_list()->item_at(0)));
+ EXPECT_TRUE(ItemObservedByFolder(
+ folder, folder->item_list()->item_at(num_observed_apps - 1)));
+ // Check that item 4 is not observed.
+ EXPECT_FALSE(ItemObservedByFolder(
+ folder, folder->item_list()->item_at(num_observed_apps)));
+}
+
} // namespace app_list
diff --git a/ui/app_list/cocoa/apps_grid_controller.h b/ui/app_list/cocoa/apps_grid_controller.h
index 77ad382..b53c814 100644
--- a/ui/app_list/cocoa/apps_grid_controller.h
+++ b/ui/app_list/cocoa/apps_grid_controller.h
@@ -23,7 +23,7 @@ class AppsGridDelegateBridge;
@protocol AppsPaginationModelObserver;
@class AppsCollectionViewDragManager;
-// Controls a grid of views, representing AppListModel::Apps sub models.
+// Controls a grid of views, representing AppListItemList sub models.
APP_LIST_EXPORT
@interface AppsGridController : NSViewController<GestureScrollDelegate,
AppListPagerDelegate,
diff --git a/ui/app_list/cocoa/apps_grid_controller.mm b/ui/app_list/cocoa/apps_grid_controller.mm
index 5fad26f..d450ef4 100644
--- a/ui/app_list/cocoa/apps_grid_controller.mm
+++ b/ui/app_list/cocoa/apps_grid_controller.mm
@@ -76,12 +76,11 @@ NSTimeInterval g_scroll_duration = 0.18;
- (void)updatePageContent:(size_t)pageIndex
resetModel:(BOOL)resetModel;
-// Bridged methods for ui::ListModelObserver.
-- (void)listItemsAdded:(size_t)start
- count:(size_t)count;
+// Bridged methods for AppListItemListObserver.
+- (void)listItemAdded:(size_t)index
+ item:(app_list::AppListItemModel*)item;
-- (void)listItemsRemoved:(size_t)start
- count:(size_t)count;
+- (void)listItemRemoved:(size_t)index;
- (void)listItemMovedFromIndex:(size_t)fromIndex
toModelIndex:(size_t)toIndex;
@@ -93,26 +92,25 @@ NSTimeInterval g_scroll_duration = 0.18;
namespace app_list {
-class AppsGridDelegateBridge : public ui::ListModelObserver {
+class AppsGridDelegateBridge : public AppListItemListObserver {
public:
AppsGridDelegateBridge(AppsGridController* parent) : parent_(parent) {}
private:
- // Overridden from ui::ListModelObserver:
- virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE {
- [parent_ listItemsAdded:start
- count:count];
+ // Overridden from AppListItemListObserver:
+ virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE {
+ [parent_ listItemAdded:index
+ item:item];
}
- virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE {
- [parent_ listItemsRemoved:start
- count:count];
+ virtual void OnListItemRemoved(size_t index,
+ AppListItemModel* item) OVERRIDE {
+ [parent_ listItemRemoved:index];
}
- virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE {
- [parent_ listItemMovedFromIndex:index
- toModelIndex:target_index];
- }
- virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE {
- NOTREACHED();
+ virtual void OnListItemMoved(size_t from_index,
+ size_t to_index,
+ AppListItemModel* item) OVERRIDE {
+ [parent_ listItemMovedFromIndex:from_index
+ toModelIndex:to_index];
}
AppsGridController* parent_; // Weak, owns us.
@@ -188,7 +186,7 @@ class AppsGridDelegateBridge : public ui::ListModelObserver {
- (void)setModel:(scoped_ptr<app_list::AppListModel>)newModel {
if (model_) {
- model_->apps()->RemoveObserver(bridge_.get());
+ model_->item_list()->RemoveObserver(bridge_.get());
// Since the model is about to be deleted, and the AppKit objects might be
// sitting in an NSAutoreleasePool, ensure there are no references to the
@@ -205,9 +203,13 @@ class AppsGridDelegateBridge : public ui::ListModelObserver {
if (!model_)
return;
- model_->apps()->AddObserver(bridge_.get());
- [self listItemsAdded:0
- count:model_->apps()->item_count()];
+ model_->item_list()->AddObserver(bridge_.get());
+ for (size_t i = 0; i < model_->item_list()->item_count(); ++i) {
+ app_list::AppListItemModel* itemModel = model_->item_list()->item_at(i);
+ [items_ insertObject:[NSValue valueWithPointer:itemModel]
+ atIndex:i];
+ }
+ [self updatePages:0];
}
- (void)setDelegate:(app_list::AppListViewDelegate*)newDelegate {
@@ -522,9 +524,9 @@ class AppsGridDelegateBridge : public ui::ListModelObserver {
if (itemIndex == modelIndex)
return;
- model_->apps()->RemoveObserver(bridge_.get());
- model_->apps()->Move(itemIndex, modelIndex);
- model_->apps()->AddObserver(bridge_.get());
+ model_->item_list()->RemoveObserver(bridge_.get());
+ model_->item_list()->MoveItem(itemIndex, modelIndex);
+ model_->item_list()->AddObserver(bridge_.get());
}
- (AppsCollectionViewDragManager*)dragManager {
@@ -535,30 +537,25 @@ class AppsGridDelegateBridge : public ui::ListModelObserver {
return scheduledScrollPage_;
}
-- (void)listItemsAdded:(size_t)start
- count:(size_t)count {
+- (void)listItemAdded:(size_t)index
+ item:(app_list::AppListItemModel*)itemModel {
// Cancel any drag, to ensure the model stays consistent.
[dragManager_ cancelDrag];
- for (size_t i = start; i < start + count; ++i) {
- app_list::AppListItemModel* itemModel = model_->apps()->GetItemAt(i);
- [items_ insertObject:[NSValue valueWithPointer:itemModel]
- atIndex:i];
- }
+ [items_ insertObject:[NSValue valueWithPointer:itemModel]
+ atIndex:index];
- [self updatePages:start];
+ [self updatePages:index];
}
-- (void)listItemsRemoved:(size_t)start
- count:(size_t)count {
+- (void)listItemRemoved:(size_t)index {
[dragManager_ cancelDrag];
// Clear the models explicitly to avoid surprises from autorelease.
- for (size_t i = start; i < start + count; ++i)
- [[self itemAtIndex:i] setModel:NULL];
+ [[self itemAtIndex:index] setModel:NULL];
- [items_ removeObjectsInRange:NSMakeRange(start, count)];
- [self updatePages:start];
+ [items_ removeObjectsInRange:NSMakeRange(index, 1)];
+ [self updatePages:index];
}
- (void)listItemMovedFromIndex:(size_t)fromIndex
diff --git a/ui/app_list/cocoa/apps_grid_controller_unittest.mm b/ui/app_list/cocoa/apps_grid_controller_unittest.mm
index df4e142..5692574 100644
--- a/ui/app_list/cocoa/apps_grid_controller_unittest.mm
+++ b/ui/app_list/cocoa/apps_grid_controller_unittest.mm
@@ -424,7 +424,7 @@ TEST_F(AppsGridControllerTest, EnsureHighlightedVisible) {
// Test runtime updates: adding items, removing items, and moving items (e.g. in
// response to app install, uninstall, and chrome sync changes. Also test
// changing titles and icons.
-TEST_F(AppsGridControllerTest, ModelUpdates) {
+TEST_F(AppsGridControllerTest, ModelUpdate) {
model()->PopulateApps(2);
EXPECT_EQ(2u, [[GetPageAt(0) content] count]);
EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
@@ -437,7 +437,7 @@ TEST_F(AppsGridControllerTest, ModelUpdates) {
EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
// Update the title via the ItemModelObserver.
- app_list::AppListItemModel* item_model = model()->apps()->GetItemAt(2);
+ app_list::AppListItemModel* item_model = model()->item_list()->item_at(2);
item_model->SetTitleAndFullName("UpdatedItem", "UpdatedItem");
EXPECT_NSEQ(@"UpdatedItem", [button title]);
EXPECT_EQ(std::string("|Item 0,Item 1,UpdatedItem|"), GetViewContent());
@@ -456,9 +456,48 @@ TEST_F(AppsGridControllerTest, ModelUpdates) {
// Icon should always be resized to 48x48.
EXPECT_EQ(kTargetImageSize, icon_size.width);
EXPECT_EQ(kTargetImageSize, icon_size.height);
+}
+
+TEST_F(AppsGridControllerTest, ModelAdd) {
+ model()->PopulateApps(2);
+ EXPECT_EQ(2u, [[GetPageAt(0) content] count]);
+ EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
+
+ app_list::AppListItemList* item_list = model()->item_list();
+
+ model()->CreateAndAddItem("Item 2");
+ ASSERT_EQ(3u, item_list->item_count());
+ EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
+ EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
+
+ // Test adding an item whose position is in the middle.
+ app_list::AppListItemModel* item0 = item_list->item_at(0);
+ app_list::AppListItemModel* item1 = item_list->item_at(1);
+ app_list::AppListItemModel* item3 =
+ model()->CreateItem("Item Three", "Item Three");
+ item3->set_position(item0->position().CreateBetween(item1->position()));
+ item_list->AddItem(item3);
+ EXPECT_EQ(4u, [apps_grid_controller_ itemCount]);
+ EXPECT_EQ(std::string("|Item 0,Item Three,Item 1,Item 2|"), GetViewContent());
+}
+
+TEST_F(AppsGridControllerTest, ModelMove) {
+ model()->PopulateApps(3);
+ EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
+ EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
+
+ // Test swapping items (e.g. rearranging via sync).
+ model()->item_list()->MoveItem(1, 2);
+ EXPECT_EQ(std::string("|Item 0,Item 2,Item 1|"), GetViewContent());
+}
+
+TEST_F(AppsGridControllerTest, ModelRemove) {
+ model()->PopulateApps(3);
+ EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
+ EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
// Test removing an item at the end.
- model()->apps()->DeleteAt(2);
+ model()->item_list()->DeleteItem("Item 2");
EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
EXPECT_EQ(std::string("|Item 0,Item 1|"), GetViewContent());
@@ -466,29 +505,34 @@ TEST_F(AppsGridControllerTest, ModelUpdates) {
model()->CreateAndAddItem("Item 2");
EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
- model()->apps()->DeleteAt(1);
+ model()->item_list()->DeleteItem("Item 1");
EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
EXPECT_EQ(std::string("|Item 0,Item 2|"), GetViewContent());
+}
- // Test inserting in the middle.
- model()->apps()->AddAt(1, model()->CreateItem("Item One", "Item One"));
- EXPECT_EQ(3u, [apps_grid_controller_ itemCount]);
- EXPECT_EQ(std::string("|Item 0,Item One,Item 2|"), GetViewContent());
-
- // Test swapping items (e.g. rearranging via sync).
- model()->apps()->Move(1, 2);
- EXPECT_EQ(std::string("|Item 0,Item 2,Item One|"), GetViewContent());
+TEST_F(AppsGridControllerTest, ModelRemoveAlll) {
+ model()->PopulateApps(3);
+ EXPECT_EQ(3u, [[GetPageAt(0) content] count]);
+ EXPECT_EQ(std::string("|Item 0,Item 1,Item 2|"), GetViewContent());
// Test removing multiple items via the model.
- model()->apps()->DeleteAll();
+ model()->item_list()->DeleteItemsByType(NULL /* all items */);
EXPECT_EQ(0u, [apps_grid_controller_ itemCount]);
EXPECT_EQ(std::string("||"), GetViewContent());
+}
- // Test removing the last item when there is one item on the second page.
- ReplaceTestModel(kItemsPerPage + 1);
+TEST_F(AppsGridControllerTest, ModelRemovePage) {
+ app_list::AppListItemList* item_list = model()->item_list();
+
+ model()->PopulateApps(kItemsPerPage + 1);
+ ASSERT_EQ(kItemsPerPage + 1, item_list->item_count());
EXPECT_EQ(kItemsPerPage + 1, [apps_grid_controller_ itemCount]);
EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
- model()->apps()->DeleteAt(kItemsPerPage);
+
+ // Test removing the last item when there is one item on the second page.
+ app_list::AppListItemModel* last_item = item_list->item_at(kItemsPerPage);
+ item_list->DeleteItem(last_item->id());
+ EXPECT_EQ(kItemsPerPage, item_list->item_count());
EXPECT_EQ(kItemsPerPage, [apps_grid_controller_ itemCount]);
EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
}
@@ -499,7 +543,7 @@ TEST_F(AppsGridControllerTest, ItemInstallProgress) {
EXPECT_EQ(2u, [apps_grid_controller_ pageCount]);
EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
app_list::AppListItemModel* item_model =
- model()->apps()->GetItemAt(kItemsPerPage);
+ model()->item_list()->item_at(kItemsPerPage);
// Highlighting an item should activate the page it is on.
item_model->SetHighlighted(true);
@@ -535,7 +579,7 @@ TEST_F(AppsGridControllerTest, ItemInstallProgress) {
// Two things can be installing simultaneously. When one starts or completes
// the model builder will ask for the item to be highlighted.
app_list::AppListItemModel* alternate_item_model =
- model()->apps()->GetItemAt(0);
+ model()->item_list()->item_at(0);
item_model->SetHighlighted(false);
alternate_item_model->SetHighlighted(true);
EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
@@ -906,8 +950,8 @@ TEST_F(AppsGridControllerTest, ScrollingWhileDragging) {
TEST_F(AppsGridControllerTest, ContextMenus) {
AppListItemWithMenu* item_two_model = new AppListItemWithMenu("Item Two");
- model()->apps()->AddAt(0, new AppListItemWithMenu("Item One"));
- model()->apps()->AddAt(1, item_two_model);
+ model()->item_list()->AddItem(new AppListItemWithMenu("Item One"));
+ model()->item_list()->AddItem(item_two_model);
EXPECT_EQ(2u, [apps_grid_controller_ itemCount]);
NSCollectionView* page = [apps_grid_controller_ collectionViewAtPageIndex:0];
diff --git a/ui/app_list/cocoa/apps_grid_view_item.mm b/ui/app_list/cocoa/apps_grid_view_item.mm
index b6e4fb5..ccd6b80 100644
--- a/ui/app_list/cocoa/apps_grid_view_item.mm
+++ b/ui/app_list/cocoa/apps_grid_view_item.mm
@@ -80,7 +80,7 @@ class ItemModelObserverBridge : public app_list::AppListItemModelObserver {
private:
AppsGridViewItem* parent_; // Weak. Owns us.
- AppListItemModel* model_; // Weak. Owned by AppListModel::Apps.
+ AppListItemModel* model_; // Weak. Owned by AppListModel.
base::scoped_nsobject<MenuController> context_menu_controller_;
DISALLOW_COPY_AND_ASSIGN(ItemModelObserverBridge);
diff --git a/ui/app_list/test/app_list_test_model.cc b/ui/app_list/test/app_list_test_model.cc
index 6f6bf10..4fd1acc 100644
--- a/ui/app_list/test/app_list_test_model.cc
+++ b/ui/app_list/test/app_list_test_model.cc
@@ -10,6 +10,9 @@
namespace app_list {
namespace test {
+// static
+const char AppListTestModel::kAppType[] = "FolderItem";
+
class AppListTestModel::AppListTestItemModel : public AppListItemModel {
public:
AppListTestItemModel(const std::string& id, AppListTestModel* model)
@@ -22,6 +25,10 @@ class AppListTestModel::AppListTestItemModel : public AppListItemModel {
model_->ItemActivated(this);
}
+ virtual const char* GetAppType() const OVERRIDE {
+ return AppListTestModel::kAppType;
+ }
+
private:
AppListTestModel* model_;
DISALLOW_COPY_AND_ASSIGN(AppListTestItemModel);
@@ -38,7 +45,7 @@ std::string AppListTestModel::GetItemName(int id) {
}
void AppListTestModel::PopulateApps(int n) {
- int start_index = apps()->item_count();
+ int start_index = item_list()->item_count();
for (int i = 0; i < n; ++i)
CreateAndAddItem(GetItemName(start_index + i));
}
@@ -49,10 +56,10 @@ void AppListTestModel::PopulateAppWithId(int id) {
std::string AppListTestModel::GetModelContent() {
std::string content;
- for (size_t i = 0; i < apps()->item_count(); ++i) {
+ for (size_t i = 0; i < item_list()->item_count(); ++i) {
if (i > 0)
content += ',';
- content += apps()->GetItemAt(i)->title();
+ content += item_list()->item_at(i)->title();
}
return content;
}
@@ -60,13 +67,20 @@ std::string AppListTestModel::GetModelContent() {
AppListItemModel* AppListTestModel::CreateItem(const std::string& title,
const std::string& full_name) {
AppListItemModel* item = new AppListTestItemModel(title, this);
+ size_t nitems = item_list()->item_count();
+ syncer::StringOrdinal position;
+ if (nitems == 0)
+ position = syncer::StringOrdinal::CreateInitialOrdinal();
+ else
+ position = item_list()->item_at(nitems - 1)->position().CreateAfter();
+ item->set_position(position);
item->SetTitleAndFullName(title, full_name);
return item;
}
void AppListTestModel::CreateAndAddItem(const std::string& title,
const std::string& full_name) {
- AddItem(CreateItem(title, full_name));
+ item_list()->AddItem(CreateItem(title, full_name));
}
void AppListTestModel::CreateAndAddItem(const std::string& title) {
@@ -74,7 +88,7 @@ void AppListTestModel::CreateAndAddItem(const std::string& title) {
}
void AppListTestModel::HighlightItemAt(int index) {
- AppListItemModel* item = apps()->GetItemAt(index);
+ AppListItemModel* item = item_list()->item_at(index);
item->SetHighlighted(true);
}
diff --git a/ui/app_list/test/app_list_test_model.h b/ui/app_list/test/app_list_test_model.h
index 548072e..473152e 100644
--- a/ui/app_list/test/app_list_test_model.h
+++ b/ui/app_list/test/app_list_test_model.h
@@ -48,6 +48,8 @@ class AppListTestModel : public AppListModel {
int activate_count() { return activate_count_; }
AppListItemModel* last_activated() { return last_activated_; }
+ static const char kAppType[];
+
private:
class AppListTestItemModel;
diff --git a/ui/app_list/views/app_list_folder_view.cc b/ui/app_list/views/app_list_folder_view.cc
index ec6e24f..44d31b8 100644
--- a/ui/app_list/views/app_list_folder_view.cc
+++ b/ui/app_list/views/app_list_folder_view.cc
@@ -55,7 +55,7 @@ AppListFolderView::~AppListFolderView() {
void AppListFolderView::SetAppListFolderItem(AppListFolderItem* folder) {
folder_item_ = folder;
- items_grid_view_->SetApps(folder_item_->apps());
+ items_grid_view_->SetItemList(folder_item_->item_list());
folder_header_view_->SetFolderItem(folder_item_);
}
@@ -93,4 +93,3 @@ void AppListFolderView::NavigateBack(AppListFolderItem* item,
}
} // namespace app_list
-
diff --git a/ui/app_list/views/app_list_item_view.h b/ui/app_list/views/app_list_item_view.h
index 311d721..08fe244 100644
--- a/ui/app_list/views/app_list_item_view.h
+++ b/ui/app_list/views/app_list_item_view.h
@@ -105,7 +105,7 @@ class APP_LIST_EXPORT AppListItemView : public views::CustomButton,
// ui::EventHandler overrides:
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
- AppListItemModel* model_; // Owned by AppListModel::Apps.
+ AppListItemModel* model_; // Owned by AppListModel.
AppsGridView* apps_grid_view_; // Owned by views hierarchy.
views::ImageView* icon_; // Owned by views hierarchy.
diff --git a/ui/app_list/views/app_list_main_view.cc b/ui/app_list/views/app_list_main_view.cc
index 0a83325..dd1a30c 100644
--- a/ui/app_list/views/app_list_main_view.cc
+++ b/ui/app_list/views/app_list_main_view.cc
@@ -161,12 +161,12 @@ void AppListMainView::PreloadIcons(PaginationModel* pagination_model,
const int tiles_per_page = kPreferredCols * kPreferredRows;
const int start_model_index = selected_page * tiles_per_page;
const int end_model_index = std::min(
- static_cast<int>(model_->apps()->item_count()),
+ static_cast<int>(model_->item_list()->item_count()),
start_model_index + tiles_per_page);
pending_icon_loaders_.clear();
for (int i = start_model_index; i < end_model_index; ++i) {
- AppListItemModel* item = model_->apps()->GetItemAt(i);
+ AppListItemModel* item = model_->item_list()->item_at(i);
if (item->icon().HasRepresentation(scale))
continue;
diff --git a/ui/app_list/views/apps_container_view.cc b/ui/app_list/views/apps_container_view.cc
index ea520b6..6becc49 100644
--- a/ui/app_list/views/apps_container_view.cc
+++ b/ui/app_list/views/apps_container_view.cc
@@ -34,7 +34,7 @@ AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view,
AddChildView(app_list_folder_view_);
apps_grid_view_->SetModel(model_);
- apps_grid_view_->SetApps(model_->apps());
+ apps_grid_view_->SetItemList(model_->item_list());
}
AppsContainerView::~AppsContainerView() {
@@ -88,6 +88,3 @@ void AppsContainerView::SetShowState(ShowState show_state) {
}
} // namespace app_list
-
-
-
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index 09d056f..d8f92c3 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -234,7 +234,7 @@ AppsGridView::AppsGridView(AppsGridViewDelegate* delegate,
PaginationModel* pagination_model,
content::WebContents* start_page_contents)
: model_(NULL),
- apps_(NULL),
+ item_list_(NULL),
delegate_(delegate),
pagination_model_(pagination_model),
page_switcher_view_(new PageSwitcher(pagination_model)),
@@ -273,8 +273,8 @@ AppsGridView::~AppsGridView() {
model_->RemoveObserver(this);
pagination_model_->RemoveObserver(this);
- if (apps_)
- apps_->RemoveObserver(this);
+ if (item_list_)
+ item_list_->RemoveObserver(this);
}
void AppsGridView::SetLayout(int icon_size, int cols, int rows_per_page) {
@@ -299,12 +299,12 @@ void AppsGridView::SetModel(AppListModel* model) {
Update();
}
-void AppsGridView::SetApps(AppListModel::Apps* apps) {
- if (apps_)
- apps_->RemoveObserver(this);
+void AppsGridView::SetItemList(AppListItemList* item_list) {
+ if (item_list_)
+ item_list_->RemoveObserver(this);
- apps_ = apps;
- apps_->AddObserver(this);
+ item_list_ = item_list;
+ item_list_->AddObserver(this);
Update();
}
@@ -631,12 +631,21 @@ void AppsGridView::ViewHierarchyChanged(
void AppsGridView::Update() {
DCHECK(!selected_view_ && !drag_view_);
- if (!apps_)
+ if (!item_list_)
return;
view_model_.Clear();
- if (apps_ && apps_->item_count())
- ListItemsAdded(0, apps_->item_count());
+ if (!item_list_->item_count())
+ return;
+ for (size_t i = 0; i < item_list_->item_count(); ++i) {
+ views::View* view = CreateViewForItemAtIndex(i);
+ view_model_.Add(view, i);
+ AddChildView(view);
+ }
+ UpdatePaging();
+ UpdatePulsingBlockViews();
+ Layout();
+ SchedulePaint();
}
void AppsGridView::UpdatePaging() {
@@ -649,7 +658,7 @@ void AppsGridView::UpdatePaging() {
void AppsGridView::UpdatePulsingBlockViews() {
const int available_slots =
- tiles_per_page() - apps_->item_count() % tiles_per_page();
+ tiles_per_page() - item_list_->item_count() % tiles_per_page();
const int desired = model_->status() == AppListModel::STATUS_SYNCING ?
available_slots : 0;
@@ -671,9 +680,9 @@ void AppsGridView::UpdatePulsingBlockViews() {
}
views::View* AppsGridView::CreateViewForItemAtIndex(size_t index) {
- DCHECK_LT(index, apps_->item_count());
+ DCHECK_LT(index, item_list_->item_count());
AppListItemView* view = new AppListItemView(this,
- apps_->GetItemAt(index));
+ item_list_->item_at(index));
view->SetIconSize(icon_size_);
#if defined(USE_AURA)
view->SetPaintToLayer(true);
@@ -1108,10 +1117,10 @@ void AppsGridView::MoveItemInModel(views::View* item_view,
if (target_model_index == current_model_index)
return;
- apps_->RemoveObserver(this);
- apps_->Move(current_model_index, target_model_index);
+ item_list_->RemoveObserver(this);
+ item_list_->MoveItem(current_model_index, target_model_index);
view_model_.Move(current_model_index, target_model_index);
- apps_->AddObserver(this);
+ item_list_->AddObserver(this);
if (pagination_model_->selected_page() != target.page)
pagination_model_->SelectPage(target.page, false);
@@ -1170,14 +1179,12 @@ void AppsGridView::LayoutStartPage() {
start_page_view_->SetBoundsRect(start_page_bounds);
}
-void AppsGridView::ListItemsAdded(size_t start, size_t count) {
+void AppsGridView::OnListItemAdded(size_t index, AppListItemModel* item) {
EndDrag(true);
- for (size_t i = start; i < start + count; ++i) {
- views::View* view = CreateViewForItemAtIndex(i);
- view_model_.Add(view, i);
- AddChildView(view);
- }
+ views::View* view = CreateViewForItemAtIndex(index);
+ view_model_.Add(view, index);
+ AddChildView(view);
UpdatePaging();
UpdatePulsingBlockViews();
@@ -1185,14 +1192,12 @@ void AppsGridView::ListItemsAdded(size_t start, size_t count) {
SchedulePaint();
}
-void AppsGridView::ListItemsRemoved(size_t start, size_t count) {
+void AppsGridView::OnListItemRemoved(size_t index, AppListItemModel* item) {
EndDrag(true);
- for (size_t i = 0; i < count; ++i) {
- views::View* view = view_model_.view_at(start);
- view_model_.Remove(start);
- delete view;
- }
+ views::View* view = view_model_.view_at(index);
+ view_model_.Remove(index);
+ delete view;
UpdatePaging();
UpdatePulsingBlockViews();
@@ -1200,18 +1205,16 @@ void AppsGridView::ListItemsRemoved(size_t start, size_t count) {
SchedulePaint();
}
-void AppsGridView::ListItemMoved(size_t index, size_t target_index) {
+void AppsGridView::OnListItemMoved(size_t from_index,
+ size_t to_index,
+ AppListItemModel* item) {
EndDrag(true);
- view_model_.Move(index, target_index);
+ view_model_.Move(from_index, to_index);
UpdatePaging();
AnimateToIdealBounds();
}
-void AppsGridView::ListItemsChanged(size_t start, size_t count) {
- NOTREACHED();
-}
-
void AppsGridView::TotalPagesChanged() {
}
diff --git a/ui/app_list/views/apps_grid_view.h b/ui/app_list/views/apps_grid_view.h
index 31f2fed..ec66746 100644
--- a/ui/app_list/views/apps_grid_view.h
+++ b/ui/app_list/views/apps_grid_view.h
@@ -48,10 +48,10 @@ class AppsGridViewDelegate;
class PageSwitcher;
class PaginationModel;
-// AppsGridView displays a grid for AppListModel::Apps sub model.
+// AppsGridView displays a grid for AppListItemList sub model.
class APP_LIST_EXPORT AppsGridView : public views::View,
public views::ButtonListener,
- public ui::ListModelObserver,
+ public AppListItemListObserver,
public PaginationModelObserver,
public AppListModelObserver {
public:
@@ -78,8 +78,9 @@ class APP_LIST_EXPORT AppsGridView : public views::View,
// Sets |model| to use. Note this does not take ownership of |model|.
void SetModel(AppListModel* model);
- // Set |apps| to renders. Note this does not take ownership of |apps|.
- void SetApps(AppListModel::Apps* apps);
+ // Sets the |item_list| to render. Note this does not take ownership of
+ // |item_list|.
+ void SetItemList(AppListItemList* item_list);
void SetSelectedView(views::View* view);
void ClearSelectedView(views::View* view);
@@ -250,11 +251,12 @@ class APP_LIST_EXPORT AppsGridView : public views::View,
virtual void ButtonPressed(views::Button* sender,
const ui::Event& event) OVERRIDE;
- // Overridden from ListModelObserver:
- virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE;
- virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE;
- virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE;
- virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE;
+ // Overridden from AppListItemListObserver:
+ virtual void OnListItemAdded(size_t index, AppListItemModel* item) OVERRIDE;
+ virtual void OnListItemRemoved(size_t index, AppListItemModel* item) OVERRIDE;
+ virtual void OnListItemMoved(size_t from_index,
+ size_t to_index,
+ AppListItemModel* item) OVERRIDE;
// Overridden from PaginationModelObserver:
virtual void TotalPagesChanged() OVERRIDE;
@@ -272,7 +274,7 @@ class APP_LIST_EXPORT AppsGridView : public views::View,
void SetViewHidden(views::View* view, bool hide, bool immediate);
AppListModel* model_; // Owned by AppListView.
- AppListModel::Apps* apps_; // Not owned.
+ AppListItemList* item_list_; // Not owned.
AppsGridViewDelegate* delegate_;
PaginationModel* pagination_model_; // Owned by AppListController.
PageSwitcher* page_switcher_view_; // Owned by views hierarchy.
diff --git a/ui/app_list/views/apps_grid_view_unittest.cc b/ui/app_list/views/apps_grid_view_unittest.cc
index 896f076..34c0c77 100644
--- a/ui/app_list/views/apps_grid_view_unittest.cc
+++ b/ui/app_list/views/apps_grid_view_unittest.cc
@@ -108,7 +108,7 @@ class AppsGridViewTest : public views::ViewsTestBase {
apps_grid_view_->SetLayout(kIconDimension, kCols, kRows);
apps_grid_view_->SetBoundsRect(gfx::Rect(gfx::Size(kWidth, kHeight)));
apps_grid_view_->SetModel(model_.get());
- apps_grid_view_->SetApps(model_->apps());
+ apps_grid_view_->SetItemList(model_->item_list());
test_api_.reset(new AppsGridViewTestApi(apps_grid_view_.get()));
}
@@ -124,7 +124,7 @@ class AppsGridViewTest : public views::ViewsTestBase {
}
AppListItemView* GetItemViewForPoint(const gfx::Point& point) {
- for (size_t i = 0; i < model_->apps()->item_count(); ++i) {
+ for (size_t i = 0; i < model_->item_list()->item_count(); ++i) {
AppListItemView* view = GetItemViewAt(i);
if (view->bounds().Contains(point))
return view;
@@ -133,7 +133,7 @@ class AppsGridViewTest : public views::ViewsTestBase {
}
gfx::Rect GetItemTileRectAt(int row, int col) {
- DCHECK_GT(model_->apps()->item_count(), 0u);
+ DCHECK_GT(model_->item_list()->item_count(), 0u);
gfx::Insets insets(apps_grid_view_->GetInsets());
gfx::Rect rect(gfx::Point(insets.left(), insets.top()),
@@ -206,7 +206,7 @@ TEST_F(AppsGridViewTest, EnsureHighlightedVisible) {
EXPECT_EQ(1, pagination_model_->selected_page());
// Highlight last one in the model and last page should be selected.
- model_->HighlightItemAt(model_->apps()->item_count() - 1);
+ model_->HighlightItemAt(model_->item_list()->item_count() - 1);
EXPECT_EQ(kPages - 1, pagination_model_->selected_page());
}
@@ -218,7 +218,7 @@ TEST_F(AppsGridViewTest, RemoveSelectedLastApp) {
AppListItemView* last_view = GetItemViewAt(kLastItemIndex);
apps_grid_view_->SetSelectedView(last_view);
- model_->apps()->DeleteAt(kLastItemIndex);
+ model_->item_list()->DeleteItem(model_->GetItemName(kLastItemIndex));
EXPECT_FALSE(apps_grid_view_->IsSelectedView(last_view));
@@ -253,7 +253,7 @@ TEST_F(AppsGridViewTest, MouseDrag) {
// Deleting an item keeps remaining intact.
SimulateDrag(AppsGridView::MOUSE, from, to);
- model_->apps()->DeleteAt(1);
+ model_->item_list()->DeleteItem(model_->GetItemName(0));
apps_grid_view_->EndDrag(false);
EXPECT_EQ(std::string("Item 1,Item 2,Item 3"),
model_->GetModelContent());