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/shelf/shelf_model.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "ash/ash_switches.h" | |
10 #include "ash/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_WINDOWED_APP: | |
26 case TYPE_PLATFORM_APP: | |
27 return 2; | |
28 case TYPE_DIALOG: | |
29 return 3; | |
30 case TYPE_APP_PANEL: | |
31 return 4; | |
32 case TYPE_IME_MENU: | |
33 return 5; | |
34 case TYPE_UNDEFINED: | |
35 NOTREACHED() << "ShelfItemType must be set"; | |
36 return -1; | |
37 } | |
38 | |
39 NOTREACHED() << "Invalid type " << type; | |
40 return 1; | |
41 } | |
42 | |
43 bool CompareByWeight(const ShelfItem& a, const ShelfItem& b) { | |
44 return ShelfItemTypeToWeight(a.type) < ShelfItemTypeToWeight(b.type); | |
45 } | |
46 | |
47 } // namespace | |
48 | |
49 ShelfModel::ShelfModel() : next_id_(1), status_(STATUS_NORMAL) { | |
50 } | |
51 | |
52 ShelfModel::~ShelfModel() { | |
53 } | |
54 | |
55 int ShelfModel::Add(const ShelfItem& item) { | |
56 return AddAt(items_.size(), item); | |
57 } | |
58 | |
59 int ShelfModel::AddAt(int index, const ShelfItem& item) { | |
60 index = ValidateInsertionIndex(item.type, index); | |
61 items_.insert(items_.begin() + index, item); | |
62 items_[index].id = next_id_++; | |
63 FOR_EACH_OBSERVER(ShelfModelObserver, observers_, ShelfItemAdded(index)); | |
64 return index; | |
65 } | |
66 | |
67 void ShelfModel::RemoveItemAt(int index) { | |
68 DCHECK(index >= 0 && index < item_count()); | |
69 // The app list and browser shortcut can't be removed. | |
70 DCHECK(items_[index].type != TYPE_APP_LIST && | |
71 items_[index].type != TYPE_BROWSER_SHORTCUT); | |
72 ShelfID id = items_[index].id; | |
73 items_.erase(items_.begin() + index); | |
74 FOR_EACH_OBSERVER(ShelfModelObserver, observers_, | |
75 ShelfItemRemoved(index, id)); | |
76 } | |
77 | |
78 void ShelfModel::Move(int index, int target_index) { | |
79 if (index == target_index) | |
80 return; | |
81 // TODO: this needs to enforce valid ranges. | |
82 ShelfItem item(items_[index]); | |
83 items_.erase(items_.begin() + index); | |
84 items_.insert(items_.begin() + target_index, item); | |
85 FOR_EACH_OBSERVER(ShelfModelObserver, observers_, | |
86 ShelfItemMoved(index, target_index)); | |
87 } | |
88 | |
89 void ShelfModel::Set(int index, const ShelfItem& item) { | |
90 DCHECK(index >= 0 && index < item_count()); | |
91 int new_index = item.type == items_[index].type ? | |
92 index : ValidateInsertionIndex(item.type, index); | |
93 | |
94 ShelfItem old_item(items_[index]); | |
95 items_[index] = item; | |
96 items_[index].id = old_item.id; | |
97 FOR_EACH_OBSERVER(ShelfModelObserver, observers_, | |
98 ShelfItemChanged(index, old_item)); | |
99 | |
100 // If the type changes confirm that the item is still in the right order. | |
101 if (new_index != index) { | |
102 // The move function works by removing one item and then inserting it at the | |
103 // new location. However - by removing the item first the order will change | |
104 // so that our target index needs to be corrected. | |
105 // TODO(skuhne): Moving this into the Move function breaks lots of unit | |
106 // tests. So several functions were already using this incorrectly. | |
107 // That needs to be cleaned up. | |
108 if (index < new_index) | |
109 new_index--; | |
110 | |
111 Move(index, new_index); | |
112 } | |
113 } | |
114 | |
115 int ShelfModel::ItemIndexByID(ShelfID id) const { | |
116 ShelfItems::const_iterator i = ItemByID(id); | |
117 return i == items_.end() ? -1 : static_cast<int>(i - items_.begin()); | |
118 } | |
119 | |
120 int ShelfModel::GetItemIndexForType(ShelfItemType type) { | |
121 for (size_t i = 0; i < items_.size(); ++i) { | |
122 if (items_[i].type == type) | |
123 return i; | |
124 } | |
125 return -1; | |
126 } | |
127 | |
128 ShelfItems::const_iterator ShelfModel::ItemByID(int id) const { | |
129 for (ShelfItems::const_iterator i = items_.begin(); | |
130 i != items_.end(); ++i) { | |
131 if (i->id == id) | |
132 return i; | |
133 } | |
134 return items_.end(); | |
135 } | |
136 | |
137 int ShelfModel::FirstRunningAppIndex() const { | |
138 // Since lower_bound only checks weights against each other, we do not need | |
139 // to explicitly change different running application types. | |
140 DCHECK_EQ(ShelfItemTypeToWeight(TYPE_WINDOWED_APP), | |
141 ShelfItemTypeToWeight(TYPE_PLATFORM_APP)); | |
142 ShelfItem weight_dummy; | |
143 weight_dummy.type = TYPE_WINDOWED_APP; | |
144 return std::lower_bound(items_.begin(), items_.end(), weight_dummy, | |
145 CompareByWeight) - items_.begin(); | |
146 } | |
147 | |
148 int ShelfModel::FirstPanelIndex() const { | |
149 ShelfItem weight_dummy; | |
150 weight_dummy.type = TYPE_APP_PANEL; | |
151 return std::lower_bound(items_.begin(), items_.end(), weight_dummy, | |
152 CompareByWeight) - items_.begin(); | |
153 } | |
154 | |
155 void ShelfModel::AddObserver(ShelfModelObserver* observer) { | |
156 observers_.AddObserver(observer); | |
157 } | |
158 | |
159 void ShelfModel::RemoveObserver(ShelfModelObserver* observer) { | |
160 observers_.RemoveObserver(observer); | |
161 } | |
162 | |
163 int ShelfModel::ValidateInsertionIndex(ShelfItemType type, int index) const { | |
164 DCHECK(index >= 0 && index <= item_count() + 1); | |
165 | |
166 // Clamp |index| to the allowed range for the type as determined by |weight|. | |
167 ShelfItem weight_dummy; | |
168 weight_dummy.type = type; | |
169 index = std::max(std::lower_bound(items_.begin(), items_.end(), weight_dummy, | |
170 CompareByWeight) - items_.begin(), | |
171 static_cast<ShelfItems::difference_type>(index)); | |
172 index = std::min(std::upper_bound(items_.begin(), items_.end(), weight_dummy, | |
173 CompareByWeight) - items_.begin(), | |
174 static_cast<ShelfItems::difference_type>(index)); | |
175 | |
176 return index; | |
177 } | |
178 | |
179 } // namespace ash | |
OLD | NEW |