blob: fbcbdd4ec22b0d3167dcbe01b0d948721d56a350 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/app_list/app_list_item_list.h"
#include "ui/app_list/app_list_item_model.h"
namespace app_list {
AppListItemList::AppListItemList() {
}
AppListItemList::~AppListItemList() {
}
void AppListItemList::AddObserver(AppListItemListObserver* observer) {
observers_.AddObserver(observer);
}
void AppListItemList::RemoveObserver(AppListItemListObserver* observer) {
observers_.RemoveObserver(observer);
}
AppListItemModel* AppListItemList::FindItem(const std::string& id) {
for (size_t i = 0; i < app_list_items_.size(); ++i) {
AppListItemModel* item = app_list_items_[i];
if (item->id() == id)
return item;
}
return NULL;
}
bool AppListItemList::FindItemIndex(const std::string& id, size_t* index) {
for (size_t i = 0; i < app_list_items_.size(); ++i) {
AppListItemModel* item = app_list_items_[i];
if (item->id() == id) {
*index = i;
return true;
}
}
return false;
}
size_t AppListItemList::AddItem(AppListItemModel* item) {
size_t index = GetItemSortOrderIndex(item);
app_list_items_.insert(app_list_items_.begin() + index, item);
FOR_EACH_OBSERVER(AppListItemListObserver,
observers_,
OnListItemAdded(index, item));
return index;
}
void AppListItemList::InsertItemAt(AppListItemModel* item, size_t index) {
DCHECK_LE(index, item_count());
if (item_count() == 0) {
AddItem(item);
return;
}
AppListItemModel* prev =
index > 0 ? app_list_items_[index - 1] : NULL;
AppListItemModel* next = index <= app_list_items_.size() - 1 ?
app_list_items_[index] : NULL;
CHECK_NE(prev, next);
if (prev && next && prev->position().Equals(next->position()))
prev = NULL;
if (!prev)
item->set_position(next->position().CreateBefore());
else if (!next)
item->set_position(prev->position().CreateAfter());
else
item->set_position(prev->position().CreateBetween(next->position()));
app_list_items_.insert(app_list_items_.begin() + index, item);
FOR_EACH_OBSERVER(AppListItemListObserver,
observers_,
OnListItemAdded(index, item));
}
void AppListItemList::DeleteItem(const std::string& id) {
scoped_ptr<AppListItemModel> item = RemoveItem(id);
// |item| will be deleted on destruction.
}
void AppListItemList::DeleteItemsByType(const char* type) {
for (int i = static_cast<int>(app_list_items_.size()) - 1;
i >= 0; --i) {
AppListItemModel* item = app_list_items_[i];
if (!type || item->GetAppType() == type)
DeleteItemAt(i);
}
}
scoped_ptr<AppListItemModel> AppListItemList::RemoveItem(
const std::string& id) {
size_t index;
if (FindItemIndex(id, &index))
return RemoveItemAt(index);
return scoped_ptr<AppListItemModel>();
}
scoped_ptr<AppListItemModel> AppListItemList::RemoveItemAt(size_t index) {
DCHECK_LT(index, item_count());
AppListItemModel* item = app_list_items_[index];
app_list_items_.weak_erase(app_list_items_.begin() + index);
FOR_EACH_OBSERVER(AppListItemListObserver,
observers_,
OnListItemRemoved(index, item));
return make_scoped_ptr<AppListItemModel>(item);
}
void AppListItemList::MoveItem(size_t from_index, size_t to_index) {
DCHECK_LT(from_index, item_count());
DCHECK_LT(to_index, item_count());
if (from_index == to_index)
return;
AppListItemModel* target_item = app_list_items_[from_index];
app_list_items_.weak_erase(app_list_items_.begin() + from_index);
app_list_items_.insert(app_list_items_.begin() + to_index, target_item);
// Update position
AppListItemModel* prev = to_index > 0 ? app_list_items_[to_index - 1] : NULL;
AppListItemModel* next = to_index < app_list_items_.size() - 1 ?
app_list_items_[to_index + 1] : NULL;
CHECK_NE(prev, next);
// It is possible that items were added with the same ordinal. Rather than
// resolving a potentially complicated chain of conflicts, just set the
// ordinal before |next| (which will place it before both items).
if (prev && next && prev->position().Equals(next->position()))
prev = NULL;
VLOG(2) << "Move: " << target_item->position().ToDebugString()
<< " Prev: " << (prev ? prev->position().ToDebugString() : "(none)")
<< " Next: " << (next ? next->position().ToDebugString() : "(none)");
if (!prev)
target_item->set_position(next->position().CreateBefore());
else if (!next)
target_item->set_position(prev->position().CreateAfter());
else
target_item->set_position(prev->position().CreateBetween(next->position()));
FOR_EACH_OBSERVER(AppListItemListObserver,
observers_,
OnListItemMoved(from_index, to_index, target_item));
}
// AppListItemList private
void AppListItemList::DeleteItemAt(size_t index) {
scoped_ptr<AppListItemModel> item = RemoveItemAt(index);
// |item| will be deleted on destruction.
}
size_t AppListItemList::GetItemSortOrderIndex(AppListItemModel* item) {
syncer::StringOrdinal position = item->position();
if (!position.IsValid()) {
size_t nitems = app_list_items_.size();
if (nitems == 0) {
position = syncer::StringOrdinal::CreateInitialOrdinal();
} else {
position = app_list_items_[nitems - 1]->position().CreateAfter();
}
item->set_position(position);
return nitems;
}
// Note: app_list_items_ is sorted by convention, but sorting is not enforced
// (items' positions might be changed outside this class).
size_t index = 0;
for (; index < app_list_items_.size(); ++index) {
if (position.LessThan(app_list_items_[index]->position()))
break;
}
return index;
}
} // namespace app_list