Updating XTBs based on .GRDs from branch master
[chromium-blink-merge.git] / ash / shelf / shelf_model.cc
blobe04af42d1f712a8b4b761f6b6e4749a3fe48d640
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"
7 #include <algorithm>
9 #include "ash/ash_switches.h"
10 #include "ash/shelf/shelf_model_observer.h"
12 namespace ash {
14 namespace {
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_UNDEFINED:
33 NOTREACHED() << "ShelfItemType must be set";
34 return -1;
37 NOTREACHED() << "Invalid type " << type;
38 return 1;
41 bool CompareByWeight(const ShelfItem& a, const ShelfItem& b) {
42 return ShelfItemTypeToWeight(a.type) < ShelfItemTypeToWeight(b.type);
45 } // namespace
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));
62 return 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)
78 return;
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]);
93 items_[index] = item;
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)
107 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)
121 return i;
123 return -1;
126 ShelfItems::const_iterator ShelfModel::ItemByID(int id) const {
127 for (ShelfItems::const_iterator i = items_.begin();
128 i != items_.end(); ++i) {
129 if (i->id == id)
130 return i;
132 return items_.end();
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)
155 return;
157 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));
182 return index;
185 } // namespace ash