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.
5 #include "ash/shelf/shelf_model.h"
9 #include "ash/ash_switches.h"
10 #include "ash/shelf/shelf_model_observer.h"
16 int ShelfItemTypeToWeight(ShelfItemType type
) {
19 // TODO(skuhne): If the app list item becomes movable again, this need
20 // to be a fallthrough.
22 case TYPE_BROWSER_SHORTCUT
:
23 case TYPE_APP_SHORTCUT
:
25 case TYPE_WINDOWED_APP
:
26 case TYPE_PLATFORM_APP
:
33 NOTREACHED() << "ShelfItemType must be set";
37 NOTREACHED() << "Invalid type " << type
;
41 bool CompareByWeight(const ShelfItem
& a
, const ShelfItem
& b
) {
42 return ShelfItemTypeToWeight(a
.type
) < ShelfItemTypeToWeight(b
.type
);
47 ShelfModel::ShelfModel() : next_id_(1), status_(STATUS_NORMAL
) {
50 ShelfModel::~ShelfModel() {
53 int ShelfModel::Add(const ShelfItem
& item
) {
54 return AddAt(items_
.size(), item
);
57 int ShelfModel::AddAt(int index
, const ShelfItem
& item
) {
58 index
= ValidateInsertionIndex(item
.type
, index
);
59 items_
.insert(items_
.begin() + index
, item
);
60 items_
[index
].id
= next_id_
++;
61 FOR_EACH_OBSERVER(ShelfModelObserver
, observers_
, ShelfItemAdded(index
));
65 void ShelfModel::RemoveItemAt(int index
) {
66 DCHECK(index
>= 0 && index
< item_count());
67 // The app list and browser shortcut can't be removed.
68 DCHECK(items_
[index
].type
!= TYPE_APP_LIST
&&
69 items_
[index
].type
!= TYPE_BROWSER_SHORTCUT
);
70 ShelfID id
= items_
[index
].id
;
71 items_
.erase(items_
.begin() + index
);
72 FOR_EACH_OBSERVER(ShelfModelObserver
, observers_
,
73 ShelfItemRemoved(index
, id
));
76 void ShelfModel::Move(int index
, int target_index
) {
77 if (index
== target_index
)
79 // TODO: this needs to enforce valid ranges.
80 ShelfItem
item(items_
[index
]);
81 items_
.erase(items_
.begin() + index
);
82 items_
.insert(items_
.begin() + target_index
, item
);
83 FOR_EACH_OBSERVER(ShelfModelObserver
, observers_
,
84 ShelfItemMoved(index
, target_index
));
87 void ShelfModel::Set(int index
, const ShelfItem
& item
) {
88 DCHECK(index
>= 0 && index
< item_count());
89 int new_index
= item
.type
== items_
[index
].type
?
90 index
: ValidateInsertionIndex(item
.type
, index
);
92 ShelfItem
old_item(items_
[index
]);
94 items_
[index
].id
= old_item
.id
;
95 FOR_EACH_OBSERVER(ShelfModelObserver
, observers_
,
96 ShelfItemChanged(index
, old_item
));
98 // If the type changes confirm that the item is still in the right order.
99 if (new_index
!= index
) {
100 // The move function works by removing one item and then inserting it at the
101 // new location. However - by removing the item first the order will change
102 // so that our target index needs to be corrected.
103 // TODO(skuhne): Moving this into the Move function breaks lots of unit
104 // tests. So several functions were already using this incorrectly.
105 // That needs to be cleaned up.
106 if (index
< new_index
)
109 Move(index
, new_index
);
113 int ShelfModel::ItemIndexByID(ShelfID id
) const {
114 ShelfItems::const_iterator i
= ItemByID(id
);
115 return i
== items_
.end() ? -1 : static_cast<int>(i
- items_
.begin());
118 int ShelfModel::GetItemIndexForType(ShelfItemType type
) {
119 for (size_t i
= 0; i
< items_
.size(); ++i
) {
120 if (items_
[i
].type
== type
)
126 ShelfItems::const_iterator
ShelfModel::ItemByID(int id
) const {
127 for (ShelfItems::const_iterator i
= items_
.begin();
128 i
!= items_
.end(); ++i
) {
135 int ShelfModel::FirstRunningAppIndex() const {
136 // Since lower_bound only checks weights against each other, we do not need
137 // to explicitly change different running application types.
138 DCHECK_EQ(ShelfItemTypeToWeight(TYPE_WINDOWED_APP
),
139 ShelfItemTypeToWeight(TYPE_PLATFORM_APP
));
140 ShelfItem weight_dummy
;
141 weight_dummy
.type
= TYPE_WINDOWED_APP
;
142 return std::lower_bound(items_
.begin(), items_
.end(), weight_dummy
,
143 CompareByWeight
) - items_
.begin();
146 int ShelfModel::FirstPanelIndex() const {
147 ShelfItem weight_dummy
;
148 weight_dummy
.type
= TYPE_APP_PANEL
;
149 return std::lower_bound(items_
.begin(), items_
.end(), weight_dummy
,
150 CompareByWeight
) - items_
.begin();
153 void ShelfModel::SetStatus(Status status
) {
154 if (status_
== status
)
158 FOR_EACH_OBSERVER(ShelfModelObserver
, observers_
, ShelfStatusChanged());
161 void ShelfModel::AddObserver(ShelfModelObserver
* observer
) {
162 observers_
.AddObserver(observer
);
165 void ShelfModel::RemoveObserver(ShelfModelObserver
* observer
) {
166 observers_
.RemoveObserver(observer
);
169 int ShelfModel::ValidateInsertionIndex(ShelfItemType type
, int index
) const {
170 DCHECK(index
>= 0 && index
<= item_count() + 1);
172 // Clamp |index| to the allowed range for the type as determined by |weight|.
173 ShelfItem weight_dummy
;
174 weight_dummy
.type
= type
;
175 index
= std::max(std::lower_bound(items_
.begin(), items_
.end(), weight_dummy
,
176 CompareByWeight
) - items_
.begin(),
177 static_cast<ShelfItems::difference_type
>(index
));
178 index
= std::min(std::upper_bound(items_
.begin(), items_
.end(), weight_dummy
,
179 CompareByWeight
) - items_
.begin(),
180 static_cast<ShelfItems::difference_type
>(index
));