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