diff options
author | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-22 11:16:58 +0000 |
---|---|---|
committer | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-22 11:16:58 +0000 |
commit | 61af999511b96b3a9adffdb657f312771e8658e3 (patch) | |
tree | 8c27d4fb8ec795c887549f33d73b6531af0a1f51 /ui/base | |
parent | c649d52d0c673eae23af01f266ae8c657d8e8fd7 (diff) | |
download | chromium_src-61af999511b96b3a9adffdb657f312771e8658e3.zip chromium_src-61af999511b96b3a9adffdb657f312771e8658e3.tar.gz chromium_src-61af999511b96b3a9adffdb657f312771e8658e3.tar.bz2 |
[Aura] Implement views-based applist.
Implement a views-based applist behind "aura-views-applist" flag.
BUG=98308,105913
TEST=Views-based app list should have no lag.
Review URL: http://codereview.chromium.org/8890049
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@115515 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base')
-rw-r--r-- | ui/base/models/list_model.h | 116 | ||||
-rw-r--r-- | ui/base/models/list_model_observer.h | 31 | ||||
-rw-r--r-- | ui/base/models/list_model_unittest.cc | 149 |
3 files changed, 296 insertions, 0 deletions
diff --git a/ui/base/models/list_model.h b/ui/base/models/list_model.h new file mode 100644 index 0000000..3634ed1 --- /dev/null +++ b/ui/base/models/list_model.h @@ -0,0 +1,116 @@ +// Copyright (c) 2011 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_BASE_MODELS_LIST_MODEL_H_ +#define UI_BASE_MODELS_LIST_MODEL_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/observer_list.h" +#include "base/memory/scoped_vector.h" +#include "ui/base/models/list_model_observer.h" + +namespace ui { + +// A list model that manages a list of ItemType pointers. Items added to the +// model are owned by the model. An item can be taken out of the model by +// RemoveAt. +template <class ItemType> +class ListModel { + public: + typedef std::vector<ItemType*> Items; + + ListModel() {} + virtual ~ListModel() {} + + // Adds |item| to the model at given |index|. + virtual void AddAt(int index, ItemType* item) { + DCHECK(index >= 0 && index <= item_count()); + items_->insert(items_.begin() + index, item); + NotifyItemsAdded(index, 1); + } + + // Removes an item at given |index| from the model. Note the removed item + // is NOT deleted and it's up to the caller to delete it. + virtual ItemType* RemoveAt(int index) { + DCHECK(index >= 0 && index < item_count()); + ItemType* item = items_[index]; + items_->erase(items_.begin() + index); + NotifyItemsRemoved(index, 1); + return item; + } + + // Removes all items from the model. This does NOT delete the items. + virtual void RemoveAll() { + int count = item_count(); + items_->clear(); + NotifyItemsRemoved(0, count); + } + + // Removes an item at given |index| from the model and deletes it. + virtual void DeleteAt(int index) { + delete RemoveAt(index); + } + + // Removes and deletes all items from the model. + virtual void DeleteAll() { + int count = item_count(); + items_.reset(); + NotifyItemsRemoved(0, count); + } + + // Convenience function to append an item to the model. + void Add(ItemType* item) { + AddAt(item_count(), item); + } + + void AddObserver(ListModelObserver* observer) { + observers_.AddObserver(observer); + } + + void RemoveObserver(ListModelObserver* observer) { + observers_.RemoveObserver(observer); + } + + void NotifyItemsAdded(int start, int count) { + FOR_EACH_OBSERVER(ListModelObserver, + observers_, + ListItemsAdded(start, count)); + } + + void NotifyItemsRemoved(int start, int count) { + FOR_EACH_OBSERVER(ListModelObserver, + observers_, + ListItemsRemoved(start, count)); + } + + void NotifyItemsChanged(int start, int count) { + FOR_EACH_OBSERVER(ListModelObserver, + observers_, + ListItemsChanged(start, count)); + } + + int item_count() const { return static_cast<int>(items_.size()); } + const Items& items() const { return items_.get(); } + + const ItemType* item_at(int index) const { + DCHECK(index >= 0 && index < item_count()); + return items_[index]; + } + ItemType* item_at(int index) { + return const_cast<ItemType*>( + const_cast<const ListModel<ItemType>*>(this)->item_at(index)); + } + + private: + ScopedVector<ItemType> items_; + ObserverList<ListModelObserver> observers_; + + DISALLOW_COPY_AND_ASSIGN(ListModel<ItemType>); +}; + +} // namespace ui + +#endif // UI_BASE_MODELS_LIST_MODEL_H_ diff --git a/ui/base/models/list_model_observer.h b/ui/base/models/list_model_observer.h new file mode 100644 index 0000000..65b22a8 --- /dev/null +++ b/ui/base/models/list_model_observer.h @@ -0,0 +1,31 @@ +// Copyright (c) 2011 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_BASE_MODELS_LIST_MODEL_OBSERVER_H_ +#define UI_BASE_MODELS_LIST_MODEL_OBSERVER_H_ +#pragma once + +#include "ui/base/ui_export.h" + +namespace ui { + +class UI_EXPORT ListModelObserver { + public: + // Invoked after items has been added to the model. + virtual void ListItemsAdded(int start, int count) = 0; + + // Invoked after items has been removed. |start| is the index before the + // removal. + virtual void ListItemsRemoved(int start, int count) = 0; + + // Invoked after items has been changed. + virtual void ListItemsChanged(int start, int count) = 0; + + protected: + virtual ~ListModelObserver() {} +}; + +} // namespace ui + +#endif // UI_BASE_MODELS_LIST_MODEL_OBSERVER_H_ diff --git a/ui/base/models/list_model_unittest.cc b/ui/base/models/list_model_unittest.cc new file mode 100644 index 0000000..1718431 --- /dev/null +++ b/ui/base/models/list_model_unittest.cc @@ -0,0 +1,149 @@ +// Copyright (c) 2011 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/base/models/list_model.h" + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ui { + +class FooItem { + public: + explicit FooItem(int id) : id_(id) {} + + int id() const { return id_; } + + private: + int id_; + DISALLOW_COPY_AND_ASSIGN(FooItem); +}; + +class ListModelTest : public testing::Test, + public ListModelObserver { + public: + ListModelTest() + : added_count_(0), + removed_count_(0), + changed_count_(0) { + } + + void ExpectCountsEqual(int added_count, + int removed_count, + int changed_count) { + EXPECT_EQ(added_count, added_count_); + EXPECT_EQ(removed_count, removed_count_); + EXPECT_EQ(changed_count, changed_count_); + } + + void ClearCounts() { + added_count_ = removed_count_ = changed_count_ = 0; + } + + // ListModelObserver implementation: + virtual void ListItemsAdded(int start, int count) OVERRIDE { + added_count_ += count; + } + virtual void ListItemsRemoved(int start, int count) OVERRIDE { + removed_count_ += count; + } + virtual void ListItemsChanged(int start, int count) OVERRIDE { + changed_count_ += count; + } + + private: + int added_count_; + int removed_count_; + int changed_count_; + + DISALLOW_COPY_AND_ASSIGN(ListModelTest); +}; + +TEST_F(ListModelTest, Add) { + ListModel<FooItem> model; + model.AddObserver(this); + + // Append FooItem(0) + model.Add(new FooItem(0)); + ExpectCountsEqual(1, 0, 0); + + // Append FooItem(1) + model.Add(new FooItem(1)); + ExpectCountsEqual(2, 0, 0); + + // Insert FooItem(2) at position 0 + model.AddAt(0, new FooItem(2)); + ExpectCountsEqual(3, 0, 0); + + // Total 3 items in mode. + EXPECT_EQ(3, model.item_count()); + + // First one should be FooItem(2), followed by FooItem(0) and FooItem(1) + EXPECT_EQ(2, model.item_at(0)->id()); + EXPECT_EQ(0, model.item_at(1)->id()); + EXPECT_EQ(1, model.item_at(2)->id()); +} + +TEST_F(ListModelTest, Remove) { + ListModel<FooItem> model; + model.AddObserver(this); + + model.Add(new FooItem(0)); + model.Add(new FooItem(1)); + model.Add(new FooItem(2)); + + ClearCounts(); + + // Remove item at index 1 from model and release memory. + model.DeleteAt(1); + ExpectCountsEqual(0, 1, 0); + + EXPECT_EQ(2, model.item_count()); + EXPECT_EQ(0, model.item_at(0)->id()); + EXPECT_EQ(2, model.item_at(1)->id()); + + // Remove all items from model and delete them. + model.DeleteAll(); + ExpectCountsEqual(0, 3, 0); +} + +TEST_F(ListModelTest, RemoveAll) { + ListModel<FooItem> model; + model.AddObserver(this); + + scoped_ptr<FooItem> foo0(new FooItem(0)); + scoped_ptr<FooItem> foo1(new FooItem(1)); + scoped_ptr<FooItem> foo2(new FooItem(2)); + + model.Add(foo0.get()); + model.Add(foo1.get()); + model.Add(foo2.get()); + + ClearCounts(); + + // Remove all items and scoped_ptr above would release memory. + model.RemoveAll(); + ExpectCountsEqual(0, 3, 0); +} + +TEST_F(ListModelTest, FakeUpdate) { + ListModel<FooItem> model; + model.AddObserver(this); + + model.Add(new FooItem(0)); + model.Add(new FooItem(1)); + model.Add(new FooItem(2)); + + ClearCounts(); + + model.NotifyItemsChanged(0, 1); + ExpectCountsEqual(0, 0, 1); + + model.NotifyItemsChanged(1, 2); + ExpectCountsEqual(0, 0, 3); +} + +} // namespace ui |