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