1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef UI_BASE_MODELS_LIST_MODEL_H_
6 #define UI_BASE_MODELS_LIST_MODEL_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/observer_list.h"
17 #include "ui/base/models/list_model_observer.h"
18 
19 namespace ui {
20 
21 // A list model that manages a list of ItemType pointers. Items added to the
22 // model are owned by the model. An item can be taken out of the model by
23 // RemoveAt.
24 template <class ItemType>
25 class ListModel {
26  public:
27   using ItemList = std::vector<std::unique_ptr<ItemType>>;
28 
ListModel()29   ListModel() {}
~ListModel()30   ~ListModel() {}
31 
32   // Adds |item| at the |index| into |items_|. Returns a raw pointer.
AddAt(size_t index,std::unique_ptr<ItemType> item)33   ItemType* AddAt(size_t index, std::unique_ptr<ItemType> item) {
34     DCHECK_LE(index, item_count());
35     ItemType* item_ptr = item.get();
36     items_.insert(items_.begin() + index, std::move(item));
37     NotifyItemsAdded(index, 1);
38     return item_ptr;
39   }
40 
41   // Convenience function to append an item to the model.
Add(std::unique_ptr<ItemType> item)42   ItemType* Add(std::unique_ptr<ItemType> item) {
43     return AddAt(item_count(), std::move(item));
44   }
45 
46   // Removes the item at |index| from |items_| without deleting it.
47   // Returns a scoped pointer containing the removed item.
RemoveAt(size_t index)48   std::unique_ptr<ItemType> RemoveAt(size_t index) {
49     DCHECK_LT(index, item_count());
50     std::unique_ptr<ItemType> item = std::move(items_[index]);
51     items_.erase(items_.begin() + index);
52     NotifyItemsRemoved(index, 1);
53     return item;
54   }
55 
56   // Removes all items from the model without deleting them.
57   // Returns a vector containing the removed items.
RemoveAll()58   ItemList RemoveAll() {
59     ItemList result;
60     result.swap(items_);
61     NotifyItemsRemoved(0, result.size());
62     return result;
63   }
64 
65   // Removes the item at |index| from |items_| and deletes it.
DeleteAt(size_t index)66   void DeleteAt(size_t index) {
67     std::unique_ptr<ItemType> item = RemoveAt(index);
68     // |item| will be deleted on destruction.
69   }
70 
71   // Removes and deletes all items from the model.
DeleteAll()72   void DeleteAll() {
73     ItemList to_be_deleted;
74     to_be_deleted.swap(items_);
75     NotifyItemsRemoved(0, to_be_deleted.size());
76   }
77 
78   // Moves the item at |index| to |target_index|. |target_index| is in terms
79   // of the model *after* the item at |index| is removed.
Move(size_t index,size_t target_index)80   void Move(size_t index, size_t target_index) {
81     DCHECK_LT(index, item_count());
82     DCHECK_LT(target_index, item_count());
83 
84     if (index == target_index)
85       return;
86 
87     std::unique_ptr<ItemType> item = std::move(items_[index]);
88     items_.erase(items_.begin() + index);
89     items_.insert(items_.begin() + target_index, std::move(item));
90     NotifyItemMoved(index, target_index);
91   }
92 
AddObserver(ListModelObserver * observer)93   void AddObserver(ListModelObserver* observer) {
94     observers_.AddObserver(observer);
95   }
96 
RemoveObserver(ListModelObserver * observer)97   void RemoveObserver(ListModelObserver* observer) {
98     observers_.RemoveObserver(observer);
99   }
100 
NotifyItemsAdded(size_t start,size_t count)101   void NotifyItemsAdded(size_t start, size_t count) {
102     for (ListModelObserver& observer : observers_)
103       observer.ListItemsAdded(start, count);
104   }
105 
NotifyItemsRemoved(size_t start,size_t count)106   void NotifyItemsRemoved(size_t start, size_t count) {
107     for (ListModelObserver& observer : observers_)
108       observer.ListItemsRemoved(start, count);
109   }
110 
NotifyItemMoved(size_t index,size_t target_index)111   void NotifyItemMoved(size_t index, size_t target_index) {
112     for (ListModelObserver& observer : observers_)
113       observer.ListItemMoved(index, target_index);
114   }
115 
NotifyItemsChanged(size_t start,size_t count)116   void NotifyItemsChanged(size_t start, size_t count) {
117     for (ListModelObserver& observer : observers_)
118       observer.ListItemsChanged(start, count);
119   }
120 
item_count()121   size_t item_count() const { return items_.size(); }
122 
GetItemAt(size_t index)123   const ItemType* GetItemAt(size_t index) const {
124     DCHECK_LT(index, item_count());
125     return items_[index].get();
126   }
GetItemAt(size_t index)127   ItemType* GetItemAt(size_t index) {
128     return const_cast<ItemType*>(
129         const_cast<const ListModel<ItemType>*>(this)->GetItemAt(index));
130   }
131 
132   // Iteration interface.
begin()133   typename ItemList::iterator begin() { return items_.begin(); }
begin()134   typename ItemList::const_iterator begin() const { return items_.begin(); }
end()135   typename ItemList::iterator end() { return items_.end(); }
end()136   typename ItemList::const_iterator end() const { return items_.end(); }
137 
138  private:
139   ItemList items_;
140   base::ObserverList<ListModelObserver>::Unchecked observers_;
141 
142   DISALLOW_COPY_AND_ASSIGN(ListModel<ItemType>);
143 };
144 
145 }  // namespace ui
146 
147 #endif  // UI_BASE_MODELS_LIST_MODEL_H_
148