• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ShelfItemTypeToWeight(ShelfItemType type)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;
35   }
36 
37   NOTREACHED() << "Invalid type " << type;
38   return 1;
39 }
40 
CompareByWeight(const ShelfItem & a,const ShelfItem & b)41 bool CompareByWeight(const ShelfItem& a, const ShelfItem& b) {
42   return ShelfItemTypeToWeight(a.type) < ShelfItemTypeToWeight(b.type);
43 }
44 
45 }  // namespace
46 
ShelfModel()47 ShelfModel::ShelfModel() : next_id_(1), status_(STATUS_NORMAL) {
48 }
49 
~ShelfModel()50 ShelfModel::~ShelfModel() {
51 }
52 
Add(const ShelfItem & item)53 int ShelfModel::Add(const ShelfItem& item) {
54   return AddAt(items_.size(), item);
55 }
56 
AddAt(int index,const ShelfItem & 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;
63 }
64 
RemoveItemAt(int 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));
74 }
75 
Move(int index,int target_index)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));
85 }
86 
Set(int index,const ShelfItem & item)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);
91 
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));
97 
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--;
108 
109     Move(index, new_index);
110   }
111 }
112 
ItemIndexByID(ShelfID id) const113 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());
116 }
117 
GetItemIndexForType(ShelfItemType type)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;
122   }
123   return -1;
124 }
125 
ItemByID(int id) const126 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;
131   }
132   return items_.end();
133 }
134 
FirstRunningAppIndex() const135 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();
144 }
145 
FirstPanelIndex() const146 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();
151 }
152 
SetStatus(Status status)153 void ShelfModel::SetStatus(Status status) {
154   if (status_ == status)
155     return;
156 
157   status_ = status;
158   FOR_EACH_OBSERVER(ShelfModelObserver, observers_, ShelfStatusChanged());
159 }
160 
AddObserver(ShelfModelObserver * observer)161 void ShelfModel::AddObserver(ShelfModelObserver* observer) {
162   observers_.AddObserver(observer);
163 }
164 
RemoveObserver(ShelfModelObserver * observer)165 void ShelfModel::RemoveObserver(ShelfModelObserver* observer) {
166   observers_.RemoveObserver(observer);
167 }
168 
ValidateInsertionIndex(ShelfItemType type,int index) const169 int ShelfModel::ValidateInsertionIndex(ShelfItemType type, int index) const {
170   DCHECK(index >= 0 && index <= item_count() + 1);
171 
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));
181 
182   return index;
183 }
184 
185 }  // namespace ash
186