OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/shelf/shelf_model.h" | 5 #include "ash/shelf/shelf_model.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "ash/public/cpp/app_launch_id.h" | |
10 #include "ash/public/cpp/shelf_item_delegate.h" | 9 #include "ash/public/cpp/shelf_item_delegate.h" |
11 #include "ash/shelf/shelf_model_observer.h" | 10 #include "ash/shelf/shelf_model_observer.h" |
12 | 11 |
13 namespace ash { | 12 namespace ash { |
14 | 13 |
15 namespace { | 14 namespace { |
16 | 15 |
17 int ShelfItemTypeToWeight(ShelfItemType type) { | 16 int ShelfItemTypeToWeight(ShelfItemType type) { |
18 switch (type) { | 17 switch (type) { |
19 case TYPE_APP_LIST: | 18 case TYPE_APP_LIST: |
(...skipping 25 matching lines...) Expand all Loading... | |
45 // Returns shelf app id. Play Store app is mapped to ARC platform host app. | 44 // Returns shelf app id. Play Store app is mapped to ARC platform host app. |
46 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 | 45 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 |
47 std::string GetShelfAppIdFromArcAppId(const std::string& arc_app_id) { | 46 std::string GetShelfAppIdFromArcAppId(const std::string& arc_app_id) { |
48 static const char kPlayStoreAppId[] = "gpkmicpkkebkmabiaedjognfppcchdfa"; | 47 static const char kPlayStoreAppId[] = "gpkmicpkkebkmabiaedjognfppcchdfa"; |
49 static const char kArcHostAppId[] = "cnbgggchhmkkdmeppjobngjoejnihlei"; | 48 static const char kArcHostAppId[] = "cnbgggchhmkkdmeppjobngjoejnihlei"; |
50 return arc_app_id == kPlayStoreAppId ? kArcHostAppId : arc_app_id; | 49 return arc_app_id == kPlayStoreAppId ? kArcHostAppId : arc_app_id; |
51 } | 50 } |
52 | 51 |
53 } // namespace | 52 } // namespace |
54 | 53 |
55 ShelfModel::ShelfModel() : next_id_(1) {} | 54 ShelfModel::ShelfModel() {} |
James Cook
2017/05/04 16:38:49
optional: = default
msw
2017/05/04 19:05:57
Done.
| |
56 | 55 |
57 ShelfModel::~ShelfModel() {} | 56 ShelfModel::~ShelfModel() {} |
58 | 57 |
59 ShelfID ShelfModel::GetShelfIDForAppID(const std::string& app_id) { | 58 ShelfID ShelfModel::GetShelfIDForAppID(const std::string& app_id) { |
60 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 | 59 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 |
61 const std::string shelf_app_id = GetShelfAppIdFromArcAppId(app_id); | 60 const std::string shelf_app_id = GetShelfAppIdFromArcAppId(app_id); |
62 | 61 |
63 if (shelf_app_id.empty()) | 62 if (shelf_app_id.empty()) |
64 return ash::kInvalidShelfID; | 63 return ShelfID(); |
65 | 64 |
66 for (const ShelfItem& item : items_) { | 65 for (const ShelfItem& item : items_) { |
67 // ShelfWindowWatcher handles app panel windows separately. | 66 // ShelfWindowWatcher handles app panel windows separately. |
68 if (item.type != TYPE_APP_PANEL && | 67 if (item.type != TYPE_APP_PANEL && item.id.app_id() == shelf_app_id) |
69 item.app_launch_id.app_id() == shelf_app_id) { | |
70 return item.id; | 68 return item.id; |
71 } | |
72 } | 69 } |
73 return kInvalidShelfID; | 70 return ShelfID(); |
74 } | 71 } |
75 | 72 |
76 ShelfID ShelfModel::GetShelfIDForAppIDAndLaunchID( | 73 ShelfID ShelfModel::GetShelfIDForAppIDAndLaunchID( |
77 const std::string& app_id, | 74 const std::string& app_id, |
78 const std::string& launch_id) { | 75 const std::string& launch_id) { |
79 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 | 76 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 |
80 const std::string shelf_app_id = GetShelfAppIdFromArcAppId(app_id); | 77 const ShelfID id = ShelfID(GetShelfAppIdFromArcAppId(app_id), launch_id); |
81 | 78 |
82 if (shelf_app_id.empty()) | 79 if (id.IsEmpty()) |
83 return ash::kInvalidShelfID; | 80 return ShelfID(); |
84 | 81 |
85 for (const ShelfItem& item : items_) { | 82 for (const ShelfItem& item : items_) { |
86 // ShelfWindowWatcher handles app panel windows separately. | 83 // ShelfWindowWatcher handles app panel windows separately. |
87 if (item.type != TYPE_APP_PANEL && | 84 if (item.type != TYPE_APP_PANEL && item.id == id) |
88 item.app_launch_id.app_id() == shelf_app_id && | |
89 item.app_launch_id.launch_id() == launch_id) { | |
90 return item.id; | 85 return item.id; |
91 } | |
92 } | 86 } |
93 return kInvalidShelfID; | 87 return ShelfID(); |
94 } | 88 } |
95 | 89 |
96 const std::string& ShelfModel::GetAppIDForShelfID(ShelfID id) { | 90 const std::string& ShelfModel::GetAppIDForShelfID(const ShelfID& id) { |
97 ShelfItems::const_iterator item = ItemByID(id); | 91 ShelfItems::const_iterator item = ItemByID(id); |
98 return item != items().end() ? item->app_launch_id.app_id() | 92 return item != items().end() ? item->id.app_id() : base::EmptyString(); |
99 : base::EmptyString(); | |
100 } | 93 } |
101 | 94 |
102 void ShelfModel::PinAppWithID(const std::string& app_id) { | 95 void ShelfModel::PinAppWithID(const std::string& app_id) { |
103 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 | 96 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 |
104 const std::string shelf_app_id = GetShelfAppIdFromArcAppId(app_id); | 97 const std::string shelf_app_id = GetShelfAppIdFromArcAppId(app_id); |
105 | 98 |
106 // If the app is already pinned, do nothing and return. | 99 // If the app is already pinned, do nothing and return. |
107 if (IsAppPinned(shelf_app_id)) | 100 if (IsAppPinned(shelf_app_id)) |
108 return; | 101 return; |
109 | 102 |
110 // Convert an existing item to be pinned, or create a new pinned item. | 103 // Convert an existing item to be pinned, or create a new pinned item. |
111 const int index = ItemIndexByID(GetShelfIDForAppID(shelf_app_id)); | 104 const int index = ItemIndexByID(GetShelfIDForAppID(shelf_app_id)); |
112 if (index >= 0) { | 105 if (index >= 0) { |
113 ShelfItem item = items_[index]; | 106 ShelfItem item = items_[index]; |
114 DCHECK_EQ(item.type, TYPE_APP); | 107 DCHECK_EQ(item.type, TYPE_APP); |
115 DCHECK(!item.pinned_by_policy); | 108 DCHECK(!item.pinned_by_policy); |
116 item.type = TYPE_PINNED_APP; | 109 item.type = TYPE_PINNED_APP; |
117 Set(index, item); | 110 Set(index, item); |
118 } else if (!shelf_app_id.empty()) { | 111 } else if (!shelf_app_id.empty()) { |
119 ash::ShelfItem item; | 112 ShelfItem item; |
120 item.type = ash::TYPE_PINNED_APP; | 113 item.type = TYPE_PINNED_APP; |
121 item.app_launch_id = AppLaunchId(shelf_app_id); | 114 item.id = ShelfID(shelf_app_id); |
122 Add(item); | 115 Add(item); |
123 } | 116 } |
124 } | 117 } |
125 | 118 |
126 bool ShelfModel::IsAppPinned(const std::string& app_id) { | 119 bool ShelfModel::IsAppPinned(const std::string& app_id) { |
127 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 | 120 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 |
128 const std::string shelf_app_id = GetShelfAppIdFromArcAppId(app_id); | 121 const std::string shelf_app_id = GetShelfAppIdFromArcAppId(app_id); |
129 | 122 |
130 const int index = ItemIndexByID(GetShelfIDForAppID(shelf_app_id)); | 123 const int index = ItemIndexByID(GetShelfIDForAppID(shelf_app_id)); |
131 return index >= 0 && (items_[index].type == TYPE_PINNED_APP || | 124 return index >= 0 && (items_[index].type == TYPE_PINNED_APP || |
132 items_[index].type == TYPE_BROWSER_SHORTCUT); | 125 items_[index].type == TYPE_BROWSER_SHORTCUT); |
133 } | 126 } |
134 | 127 |
135 void ShelfModel::UnpinAppWithID(const std::string& app_id) { | 128 void ShelfModel::UnpinAppWithID(const std::string& app_id) { |
136 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 | 129 // TODO(khmel): Fix this Arc application id mapping. See http://b/31703859 |
137 const std::string shelf_app_id = GetShelfAppIdFromArcAppId(app_id); | 130 const std::string shelf_app_id = GetShelfAppIdFromArcAppId(app_id); |
138 | 131 |
139 // If the app is already not pinned, do nothing and return. | 132 // If the app is already not pinned, do nothing and return. |
140 if (!IsAppPinned(shelf_app_id)) | 133 if (!IsAppPinned(shelf_app_id)) |
141 return; | 134 return; |
142 | 135 |
143 // Remove the item if it is closed, or mark it as unpinned. | 136 // Remove the item if it is closed, or mark it as unpinned. |
144 const int index = ItemIndexByID(GetShelfIDForAppID(shelf_app_id)); | 137 const int index = ItemIndexByID(GetShelfIDForAppID(shelf_app_id)); |
145 ShelfItem item = items_[index]; | 138 ShelfItem item = items_[index]; |
146 DCHECK_EQ(item.type, TYPE_PINNED_APP); | 139 DCHECK_EQ(item.type, TYPE_PINNED_APP); |
147 DCHECK(!item.pinned_by_policy); | 140 DCHECK(!item.pinned_by_policy); |
148 if (item.status == ash::STATUS_CLOSED) { | 141 if (item.status == STATUS_CLOSED) { |
James Cook
2017/05/04 16:38:49
I think it's really nice that you clean up these s
msw
2017/05/04 19:05:57
Acknowledged.
| |
149 RemoveItemAt(index); | 142 RemoveItemAt(index); |
150 } else { | 143 } else { |
151 item.type = TYPE_APP; | 144 item.type = TYPE_APP; |
152 Set(index, item); | 145 Set(index, item); |
153 } | 146 } |
154 } | 147 } |
155 | 148 |
156 void ShelfModel::DestroyItemDelegates() { | 149 void ShelfModel::DestroyItemDelegates() { |
157 // Some ShelfItemDelegates access this model in their destructors and hence | 150 // Some ShelfItemDelegates access this model in their destructors and hence |
158 // need early cleanup. | 151 // need early cleanup. |
159 id_to_item_delegate_map_.clear(); | 152 id_to_item_delegate_map_.clear(); |
160 } | 153 } |
161 | 154 |
162 int ShelfModel::Add(const ShelfItem& item) { | 155 int ShelfModel::Add(const ShelfItem& item) { |
163 return AddAt(items_.size(), item); | 156 return AddAt(items_.size(), item); |
164 } | 157 } |
165 | 158 |
166 int ShelfModel::AddAt(int index, const ShelfItem& item) { | 159 int ShelfModel::AddAt(int index, const ShelfItem& item) { |
160 // Items should have unique non-empty ids to avoid undefined model behavior. | |
161 DCHECK(!item.id.IsEmpty()); | |
162 DCHECK_EQ(ItemIndexByID(item.id), -1); | |
167 index = ValidateInsertionIndex(item.type, index); | 163 index = ValidateInsertionIndex(item.type, index); |
168 items_.insert(items_.begin() + index, item); | 164 items_.insert(items_.begin() + index, item); |
169 items_[index].id = next_id_++; | |
170 for (auto& observer : observers_) | 165 for (auto& observer : observers_) |
171 observer.ShelfItemAdded(index); | 166 observer.ShelfItemAdded(index); |
172 return index; | 167 return index; |
173 } | 168 } |
174 | 169 |
175 void ShelfModel::RemoveItemAt(int index) { | 170 void ShelfModel::RemoveItemAt(int index) { |
176 DCHECK(index >= 0 && index < item_count()); | 171 DCHECK(index >= 0 && index < item_count()); |
177 ShelfItem old_item(items_[index]); | 172 ShelfItem old_item(items_[index]); |
178 items_.erase(items_.begin() + index); | 173 items_.erase(items_.begin() + index); |
179 id_to_item_delegate_map_.erase(old_item.id); | 174 id_to_item_delegate_map_.erase(old_item.id); |
(...skipping 17 matching lines...) Expand all Loading... | |
197 NOTREACHED(); | 192 NOTREACHED(); |
198 return; | 193 return; |
199 } | 194 } |
200 | 195 |
201 int new_index = item.type == items_[index].type | 196 int new_index = item.type == items_[index].type |
202 ? index | 197 ? index |
203 : ValidateInsertionIndex(item.type, index); | 198 : ValidateInsertionIndex(item.type, index); |
204 | 199 |
205 ShelfItem old_item(items_[index]); | 200 ShelfItem old_item(items_[index]); |
206 items_[index] = item; | 201 items_[index] = item; |
207 items_[index].id = old_item.id; | 202 DCHECK(old_item.id == item.id); |
208 for (auto& observer : observers_) | 203 for (auto& observer : observers_) |
209 observer.ShelfItemChanged(index, old_item); | 204 observer.ShelfItemChanged(index, old_item); |
210 | 205 |
211 // If the type changes confirm that the item is still in the right order. | 206 // If the type changes confirm that the item is still in the right order. |
212 if (new_index != index) { | 207 if (new_index != index) { |
213 // The move function works by removing one item and then inserting it at the | 208 // The move function works by removing one item and then inserting it at the |
214 // new location. However - by removing the item first the order will change | 209 // new location. However - by removing the item first the order will change |
215 // so that our target index needs to be corrected. | 210 // so that our target index needs to be corrected. |
216 // TODO(skuhne): Moving this into the Move function breaks lots of unit | 211 // TODO(skuhne): Moving this into the Move function breaks lots of unit |
217 // tests. So several functions were already using this incorrectly. | 212 // tests. So several functions were already using this incorrectly. |
218 // That needs to be cleaned up. | 213 // That needs to be cleaned up. |
219 if (index < new_index) | 214 if (index < new_index) |
220 new_index--; | 215 new_index--; |
221 | 216 |
222 Move(index, new_index); | 217 Move(index, new_index); |
223 } | 218 } |
224 } | 219 } |
225 | 220 |
226 int ShelfModel::ItemIndexByID(ShelfID id) const { | 221 int ShelfModel::ItemIndexByID(const ShelfID& id) const { |
227 ShelfItems::const_iterator i = ItemByID(id); | 222 ShelfItems::const_iterator i = ItemByID(id); |
228 return i == items_.end() ? -1 : static_cast<int>(i - items_.begin()); | 223 return i == items_.end() ? -1 : static_cast<int>(i - items_.begin()); |
229 } | 224 } |
230 | 225 |
231 int ShelfModel::GetItemIndexForType(ShelfItemType type) { | 226 int ShelfModel::GetItemIndexForType(ShelfItemType type) { |
232 for (size_t i = 0; i < items_.size(); ++i) { | 227 for (size_t i = 0; i < items_.size(); ++i) { |
233 if (items_[i].type == type) | 228 if (items_[i].type == type) |
234 return i; | 229 return i; |
235 } | 230 } |
236 return -1; | 231 return -1; |
237 } | 232 } |
238 | 233 |
239 ShelfItems::const_iterator ShelfModel::ItemByID(ShelfID id) const { | 234 ShelfItems::const_iterator ShelfModel::ItemByID(const ShelfID& id) const { |
240 for (ShelfItems::const_iterator i = items_.begin(); i != items_.end(); ++i) { | 235 for (ShelfItems::const_iterator i = items_.begin(); i != items_.end(); ++i) { |
241 if (i->id == id) | 236 if (i->id == id) |
242 return i; | 237 return i; |
243 } | 238 } |
244 return items_.end(); | 239 return items_.end(); |
245 } | 240 } |
246 | 241 |
247 int ShelfModel::FirstRunningAppIndex() const { | 242 int ShelfModel::FirstRunningAppIndex() const { |
248 ShelfItem weight_dummy; | 243 ShelfItem weight_dummy; |
249 weight_dummy.type = TYPE_APP; | 244 weight_dummy.type = TYPE_APP; |
250 return std::lower_bound(items_.begin(), items_.end(), weight_dummy, | 245 return std::lower_bound(items_.begin(), items_.end(), weight_dummy, |
251 CompareByWeight) - | 246 CompareByWeight) - |
252 items_.begin(); | 247 items_.begin(); |
253 } | 248 } |
254 | 249 |
255 int ShelfModel::FirstPanelIndex() const { | 250 int ShelfModel::FirstPanelIndex() const { |
256 ShelfItem weight_dummy; | 251 ShelfItem weight_dummy; |
257 weight_dummy.type = TYPE_APP_PANEL; | 252 weight_dummy.type = TYPE_APP_PANEL; |
258 return std::lower_bound(items_.begin(), items_.end(), weight_dummy, | 253 return std::lower_bound(items_.begin(), items_.end(), weight_dummy, |
259 CompareByWeight) - | 254 CompareByWeight) - |
260 items_.begin(); | 255 items_.begin(); |
261 } | 256 } |
262 | 257 |
263 void ShelfModel::SetShelfItemDelegate( | 258 void ShelfModel::SetShelfItemDelegate( |
264 ShelfID id, | 259 const ShelfID& id, |
265 std::unique_ptr<ShelfItemDelegate> item_delegate) { | 260 std::unique_ptr<ShelfItemDelegate> item_delegate) { |
266 if (item_delegate) | 261 if (item_delegate) |
267 item_delegate->set_shelf_id(id); | 262 item_delegate->set_shelf_id(id); |
268 // This assignment replaces any ShelfItemDelegate already registered for |id|. | 263 // This assignment replaces any ShelfItemDelegate already registered for |id|. |
269 id_to_item_delegate_map_[id] = std::move(item_delegate); | 264 id_to_item_delegate_map_[id] = std::move(item_delegate); |
270 } | 265 } |
271 | 266 |
272 ShelfItemDelegate* ShelfModel::GetShelfItemDelegate(ShelfID id) { | 267 ShelfItemDelegate* ShelfModel::GetShelfItemDelegate(const ShelfID& id) { |
273 if (id_to_item_delegate_map_.find(id) != id_to_item_delegate_map_.end()) | 268 if (id_to_item_delegate_map_.find(id) != id_to_item_delegate_map_.end()) |
274 return id_to_item_delegate_map_[id].get(); | 269 return id_to_item_delegate_map_[id].get(); |
275 return nullptr; | 270 return nullptr; |
276 } | 271 } |
277 | 272 |
278 void ShelfModel::AddObserver(ShelfModelObserver* observer) { | 273 void ShelfModel::AddObserver(ShelfModelObserver* observer) { |
279 observers_.AddObserver(observer); | 274 observers_.AddObserver(observer); |
280 } | 275 } |
281 | 276 |
282 void ShelfModel::RemoveObserver(ShelfModelObserver* observer) { | 277 void ShelfModel::RemoveObserver(ShelfModelObserver* observer) { |
(...skipping 12 matching lines...) Expand all Loading... | |
295 static_cast<ShelfItems::difference_type>(index)); | 290 static_cast<ShelfItems::difference_type>(index)); |
296 index = std::min(std::upper_bound(items_.begin(), items_.end(), weight_dummy, | 291 index = std::min(std::upper_bound(items_.begin(), items_.end(), weight_dummy, |
297 CompareByWeight) - | 292 CompareByWeight) - |
298 items_.begin(), | 293 items_.begin(), |
299 static_cast<ShelfItems::difference_type>(index)); | 294 static_cast<ShelfItems::difference_type>(index)); |
300 | 295 |
301 return index; | 296 return index; |
302 } | 297 } |
303 | 298 |
304 } // namespace ash | 299 } // namespace ash |
OLD | NEW |