OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 #include "ash/common/shelf/shelf_model.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "ash/common/shelf/shelf_item_delegate.h" | |
10 #include "ash/common/shelf/shelf_model_observer.h" | |
11 | |
12 namespace ash { | |
13 | |
14 namespace { | |
15 | |
16 int ShelfItemTypeToWeight(ShelfItemType type) { | |
17 switch (type) { | |
18 case TYPE_APP_LIST: | |
19 // TODO(skuhne): If the app list item becomes movable again, this need | |
20 // to be a fallthrough. | |
21 return 0; | |
22 case TYPE_BROWSER_SHORTCUT: | |
23 case TYPE_APP_SHORTCUT: | |
24 return 1; | |
25 case TYPE_APP: | |
26 return 2; | |
27 case TYPE_DIALOG: | |
28 return 3; | |
29 case TYPE_APP_PANEL: | |
30 return 4; | |
31 case TYPE_UNDEFINED: | |
32 NOTREACHED() << "ShelfItemType must be set"; | |
33 return -1; | |
34 } | |
35 | |
36 NOTREACHED() << "Invalid type " << type; | |
37 return 1; | |
38 } | |
39 | |
40 bool CompareByWeight(const ShelfItem& a, const ShelfItem& b) { | |
41 return ShelfItemTypeToWeight(a.type) < ShelfItemTypeToWeight(b.type); | |
42 } | |
43 | |
44 } // namespace | |
45 | |
46 ShelfModel::ShelfModel() : next_id_(1) {} | |
47 | |
48 ShelfModel::~ShelfModel() {} | |
49 | |
50 void ShelfModel::DestroyItemDelegates() { | |
51 // Some ShelfItemDelegates access this model in their destructors and hence | |
52 // need early cleanup. | |
53 id_to_item_delegate_map_.clear(); | |
54 } | |
55 | |
56 int ShelfModel::Add(const ShelfItem& item) { | |
57 return AddAt(items_.size(), item); | |
58 } | |
59 | |
60 int ShelfModel::AddAt(int index, const ShelfItem& item) { | |
61 index = ValidateInsertionIndex(item.type, index); | |
62 items_.insert(items_.begin() + index, item); | |
63 items_[index].id = next_id_++; | |
64 for (auto& observer : observers_) | |
65 observer.ShelfItemAdded(index); | |
66 return index; | |
67 } | |
68 | |
69 void ShelfModel::RemoveItemAt(int index) { | |
70 DCHECK(index >= 0 && index < item_count()); | |
71 ShelfID id = items_[index].id; | |
72 items_.erase(items_.begin() + index); | |
73 RemoveShelfItemDelegate(id); | |
74 // TODO(jamescook): Fold this into ShelfItemRemoved in existing observers. | |
75 for (auto& observer : observers_) | |
76 observer.OnSetShelfItemDelegate(id, nullptr); | |
77 for (auto& observer : observers_) | |
78 observer.ShelfItemRemoved(index, id); | |
79 } | |
80 | |
81 void ShelfModel::Move(int index, int target_index) { | |
82 if (index == target_index) | |
83 return; | |
84 // TODO: this needs to enforce valid ranges. | |
85 ShelfItem item(items_[index]); | |
86 items_.erase(items_.begin() + index); | |
87 items_.insert(items_.begin() + target_index, item); | |
88 for (auto& observer : observers_) | |
89 observer.ShelfItemMoved(index, target_index); | |
90 } | |
91 | |
92 void ShelfModel::Set(int index, const ShelfItem& item) { | |
93 if (index < 0 || index >= item_count()) { | |
94 NOTREACHED(); | |
95 return; | |
96 } | |
97 | |
98 int new_index = item.type == items_[index].type | |
99 ? index | |
100 : ValidateInsertionIndex(item.type, index); | |
101 | |
102 ShelfItem old_item(items_[index]); | |
103 items_[index] = item; | |
104 items_[index].id = old_item.id; | |
105 for (auto& observer : observers_) | |
106 observer.ShelfItemChanged(index, old_item); | |
107 | |
108 // If the type changes confirm that the item is still in the right order. | |
109 if (new_index != index) { | |
110 // The move function works by removing one item and then inserting it at the | |
111 // new location. However - by removing the item first the order will change | |
112 // so that our target index needs to be corrected. | |
113 // TODO(skuhne): Moving this into the Move function breaks lots of unit | |
114 // tests. So several functions were already using this incorrectly. | |
115 // That needs to be cleaned up. | |
116 if (index < new_index) | |
117 new_index--; | |
118 | |
119 Move(index, new_index); | |
120 } | |
121 } | |
122 | |
123 int ShelfModel::ItemIndexByID(ShelfID id) const { | |
124 ShelfItems::const_iterator i = ItemByID(id); | |
125 return i == items_.end() ? -1 : static_cast<int>(i - items_.begin()); | |
126 } | |
127 | |
128 int ShelfModel::GetItemIndexForType(ShelfItemType type) { | |
129 for (size_t i = 0; i < items_.size(); ++i) { | |
130 if (items_[i].type == type) | |
131 return i; | |
132 } | |
133 return -1; | |
134 } | |
135 | |
136 ShelfItems::const_iterator ShelfModel::ItemByID(int id) const { | |
137 for (ShelfItems::const_iterator i = items_.begin(); i != items_.end(); ++i) { | |
138 if (i->id == id) | |
139 return i; | |
140 } | |
141 return items_.end(); | |
142 } | |
143 | |
144 int ShelfModel::FirstRunningAppIndex() const { | |
145 ShelfItem weight_dummy; | |
146 weight_dummy.type = TYPE_APP; | |
147 return std::lower_bound(items_.begin(), items_.end(), weight_dummy, | |
148 CompareByWeight) - | |
149 items_.begin(); | |
150 } | |
151 | |
152 int ShelfModel::FirstPanelIndex() const { | |
153 ShelfItem weight_dummy; | |
154 weight_dummy.type = TYPE_APP_PANEL; | |
155 return std::lower_bound(items_.begin(), items_.end(), weight_dummy, | |
156 CompareByWeight) - | |
157 items_.begin(); | |
158 } | |
159 | |
160 void ShelfModel::SetShelfItemDelegate( | |
161 ShelfID id, | |
162 std::unique_ptr<ShelfItemDelegate> item_delegate) { | |
163 // If another ShelfItemDelegate is already registered for |id|, we assume | |
164 // that this request is replacing ShelfItemDelegate for |id| with | |
165 // |item_delegate|. | |
166 RemoveShelfItemDelegate(id); | |
167 | |
168 for (auto& observer : observers_) | |
169 observer.OnSetShelfItemDelegate(id, item_delegate.get()); | |
170 | |
171 id_to_item_delegate_map_[id] = std::move(item_delegate); | |
172 } | |
173 | |
174 ShelfItemDelegate* ShelfModel::GetShelfItemDelegate(ShelfID id) { | |
175 if (id_to_item_delegate_map_.find(id) != id_to_item_delegate_map_.end()) | |
176 return id_to_item_delegate_map_[id].get(); | |
177 return nullptr; | |
178 } | |
179 | |
180 void ShelfModel::AddObserver(ShelfModelObserver* observer) { | |
181 observers_.AddObserver(observer); | |
182 } | |
183 | |
184 void ShelfModel::RemoveObserver(ShelfModelObserver* observer) { | |
185 observers_.RemoveObserver(observer); | |
186 } | |
187 | |
188 int ShelfModel::ValidateInsertionIndex(ShelfItemType type, int index) const { | |
189 DCHECK(index >= 0 && index <= item_count() + 1); | |
190 | |
191 // Clamp |index| to the allowed range for the type as determined by |weight|. | |
192 ShelfItem weight_dummy; | |
193 weight_dummy.type = type; | |
194 index = std::max(std::lower_bound(items_.begin(), items_.end(), weight_dummy, | |
195 CompareByWeight) - | |
196 items_.begin(), | |
197 static_cast<ShelfItems::difference_type>(index)); | |
198 index = std::min(std::upper_bound(items_.begin(), items_.end(), weight_dummy, | |
199 CompareByWeight) - | |
200 items_.begin(), | |
201 static_cast<ShelfItems::difference_type>(index)); | |
202 | |
203 return index; | |
204 } | |
205 | |
206 void ShelfModel::RemoveShelfItemDelegate(ShelfID id) { | |
207 if (id_to_item_delegate_map_.find(id) != id_to_item_delegate_map_.end()) | |
208 id_to_item_delegate_map_.erase(id); | |
209 } | |
210 | |
211 } // namespace ash | |
OLD | NEW |