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.
5 #include "ash/launcher/launcher_model.h"
9 #include "ash/ash_switches.h"
10 #include "ash/launcher/launcher_model_observer.h"
16 int LauncherItemTypeToWeight(LauncherItemType type
) {
17 if (ash::switches::UseAlternateShelfLayout()) {
20 // TODO(skuhne): If the app list item becomes movable again, this need
21 // to be a fallthrough.
23 case TYPE_BROWSER_SHORTCUT
:
24 case TYPE_APP_SHORTCUT
:
25 case TYPE_WINDOWED_APP
:
27 case TYPE_PLATFORM_APP
:
32 NOTREACHED() << "LauncherItemType must be set";
37 case TYPE_BROWSER_SHORTCUT
:
38 case TYPE_APP_SHORTCUT
:
39 case TYPE_WINDOWED_APP
:
41 case TYPE_PLATFORM_APP
:
48 NOTREACHED() << "LauncherItemType must be set";
53 NOTREACHED() << "Invalid type " << type
;
57 bool CompareByWeight(const LauncherItem
& a
, const LauncherItem
& b
) {
58 return LauncherItemTypeToWeight(a
.type
) < LauncherItemTypeToWeight(b
.type
);
63 LauncherModel::LauncherModel() : next_id_(1), status_(STATUS_NORMAL
) {
66 LauncherModel::~LauncherModel() {
69 int LauncherModel::Add(const LauncherItem
& item
) {
70 return AddAt(items_
.size(), item
);
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(LauncherModelObserver
, observers_
,
78 LauncherItemAdded(index
));
82 void LauncherModel::RemoveItemAt(int index
) {
83 DCHECK(index
>= 0 && index
< item_count());
84 // The app list and browser shortcut can't be removed.
85 DCHECK(items_
[index
].type
!= TYPE_APP_LIST
&&
86 items_
[index
].type
!= TYPE_BROWSER_SHORTCUT
);
87 LauncherID id
= items_
[index
].id
;
88 items_
.erase(items_
.begin() + index
);
89 FOR_EACH_OBSERVER(LauncherModelObserver
, observers_
,
90 LauncherItemRemoved(index
, id
));
93 void LauncherModel::Move(int index
, int target_index
) {
94 if (index
== target_index
)
96 // TODO: this needs to enforce valid ranges.
97 LauncherItem
item(items_
[index
]);
98 items_
.erase(items_
.begin() + index
);
99 items_
.insert(items_
.begin() + target_index
, item
);
100 FOR_EACH_OBSERVER(LauncherModelObserver
, observers_
,
101 LauncherItemMoved(index
, target_index
));
104 void LauncherModel::Set(int index
, const LauncherItem
& item
) {
105 DCHECK(index
>= 0 && index
< item_count());
106 int new_index
= item
.type
== items_
[index
].type
?
107 index
: ValidateInsertionIndex(item
.type
, index
);
109 LauncherItem
old_item(items_
[index
]);
110 items_
[index
] = item
;
111 items_
[index
].id
= old_item
.id
;
112 FOR_EACH_OBSERVER(LauncherModelObserver
, observers_
,
113 LauncherItemChanged(index
, old_item
));
115 // If the type changes confirm that the item is still in the right order.
116 if (new_index
!= index
) {
117 // The move function works by removing one item and then inserting it at the
118 // new location. However - by removing the item first the order will change
119 // so that our target index needs to be corrected.
120 // TODO(skuhne): Moving this into the Move function breaks lots of unit
121 // tests. So several functions were already using this incorrectly.
122 // That needs to be cleaned up.
123 if (index
< new_index
)
126 Move(index
, new_index
);
130 int LauncherModel::ItemIndexByID(LauncherID id
) const {
131 LauncherItems::const_iterator i
= ItemByID(id
);
132 return i
== items_
.end() ? -1 : static_cast<int>(i
- items_
.begin());
135 LauncherItems::const_iterator
LauncherModel::ItemByID(int id
) const {
136 for (LauncherItems::const_iterator i
= items_
.begin();
137 i
!= items_
.end(); ++i
) {
144 int LauncherModel::FirstPanelIndex() const {
145 LauncherItem weight_dummy
;
146 weight_dummy
.type
= TYPE_APP_PANEL
;
147 return std::lower_bound(items_
.begin(), items_
.end(), weight_dummy
,
148 CompareByWeight
) - items_
.begin();
151 void LauncherModel::SetStatus(Status status
) {
152 if (status_
== status
)
156 FOR_EACH_OBSERVER(LauncherModelObserver
, observers_
,
157 LauncherStatusChanged());
160 void LauncherModel::AddObserver(LauncherModelObserver
* observer
) {
161 observers_
.AddObserver(observer
);
164 void LauncherModel::RemoveObserver(LauncherModelObserver
* observer
) {
165 observers_
.RemoveObserver(observer
);
168 int LauncherModel::ValidateInsertionIndex(LauncherItemType type
,
170 DCHECK(index
>= 0 && index
<= item_count() +
171 (ash::switches::UseAlternateShelfLayout() ? 1 : 0));
173 // Clamp |index| to the allowed range for the type as determined by |weight|.
174 LauncherItem weight_dummy
;
175 weight_dummy
.type
= type
;
176 index
= std::max(std::lower_bound(items_
.begin(), items_
.end(), weight_dummy
,
177 CompareByWeight
) - items_
.begin(),
178 static_cast<LauncherItems::difference_type
>(index
));
179 index
= std::min(std::upper_bound(items_
.begin(), items_
.end(), weight_dummy
,
180 CompareByWeight
) - items_
.begin(),
181 static_cast<LauncherItems::difference_type
>(index
));