// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/app_list/model/app_list_test_model.h"
#include <stddef.h>
#include <memory>
#include <utility>
#include <vector>
#include "ash/public/cpp/app_list/app_list_config.h"
#include "ash/public/cpp/app_list/app_list_controller.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/models/menu_model.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_unittest_util.h"
namespace ash {
namespace test {
gfx::ImageSkia CreateImageSkia(int width, int height) {
SkBitmap bitmap;
bitmap.allocN32Pixels(width, height);
bitmap.eraseARGB(255, 0, 255, 0);
return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
}
// static
const char AppListTestModel::kItemType[] = "TestItem";
// AppListTestModel::AppListTestItem
AppListTestModel::AppListTestItem::AppListTestItem(const std::string& id,
AppListTestModel* model)
: AppListItem(id), model_(model) {
const int icon_dimension =
SharedAppListConfig::instance().default_grid_icon_dimension();
SetDefaultIconAndColor(CreateImageSkia(icon_dimension, icon_dimension),
IconColor(), /*is_placeholder_icon=*/false);
}
AppListTestModel::AppListTestItem::~AppListTestItem() = default;
void AppListTestModel::AppListTestItem::Activate(int event_flags) {
model_->ItemActivated(this);
}
std::unique_ptr<ui::SimpleMenuModel>
AppListTestModel::AppListTestItem::CreateContextMenuModel() {
auto menu_model = std::make_unique<ui::SimpleMenuModel>(
nullptr /*no SimpleMenuModelDelegate for tests*/);
menu_model->AddItem(0, u"0");
menu_model->AddItem(1, u"1");
return menu_model;
}
const char* AppListTestModel::AppListTestItem::GetItemType() const {
return AppListTestModel::kItemType;
}
void AppListTestModel::AppListTestItem::SetPosition(
const syncer::StringOrdinal& new_position) {
set_position(new_position);
}
// AppListTestModel
AppListTestModel::AppListTestModel()
: AppListModel(/*app_list_model_delegate=*/this) {}
AppListTestModel::~AppListTestModel() = default;
AppListItem* AppListTestModel::AddItem(AppListItem* item) {
return AppListModel::AddItem(base::WrapUnique(item));
}
void AppListTestModel::RequestPositionUpdate(
std::string id,
const syncer::StringOrdinal& new_position,
RequestPositionUpdateReason reason) {
// Copy the logic of `ChromeAppListModelUpdater::HandleSetPosition()`.
auto metadata = FindItem(id)->CloneMetadata();
metadata->position = new_position;
SetItemMetadata(id, std::move(metadata));
}
void AppListTestModel::RequestMoveItemToFolder(std::string id,
const std::string& folder_id) {
// Copy the logic of `ChromeAppListModelUpdater::RequestMoveItemToFolder()`.
AppListFolderItem* dest_folder = FindFolderItem(folder_id);
DCHECK(dest_folder);
const syncer::StringOrdinal target_position =
dest_folder->item_list()->CreatePositionBefore(syncer::StringOrdinal());
auto metadata = FindItem(id)->CloneMetadata();
metadata->folder_id = folder_id;
metadata->position = target_position;
SetItemMetadata(id, std::move(metadata));
}
void AppListTestModel::RequestMoveItemToRoot(
std::string id,
syncer::StringOrdinal target_position) {
// Copy the logic of `ChromeAppListModelUpdater::RequestMoveItemToRoot()`.
auto metadata = FindItem(id)->CloneMetadata();
metadata->folder_id = "";
metadata->position = target_position;
SetItemMetadata(id, std::move(metadata));
}
std::string AppListTestModel::RequestFolderCreation(
std::string merge_target_id,
std::string item_to_merge_id) {
auto target_item_metadata = FindItem(merge_target_id)->CloneMetadata();
const syncer::StringOrdinal target_item_position =
target_item_metadata->position;
const std::string folder_id = AppListFolderItem::GenerateId();
auto folder = std::make_unique<AppListFolderItem>(
folder_id, /*app_list_model_delegate=*/this);
auto folder_metadata = folder->CloneMetadata();
folder_metadata->position = target_item_position;
folder->SetMetadata(std::move(folder_metadata));
AddItem(folder.release());
target_item_metadata->folder_id = folder_id;
SetItemMetadata(merge_target_id, std::move(target_item_metadata));
auto item_to_merge_metadata = FindItem(item_to_merge_id)->CloneMetadata();
item_to_merge_metadata->position = target_item_position.CreateAfter();
item_to_merge_metadata->folder_id = folder_id;
SetItemMetadata(item_to_merge_id, std::move(item_to_merge_metadata));
return folder_id;
}
void AppListTestModel::RequestFolderRename(std::string id,
const std::string& new_name) {
auto metadata = FindItem(id)->CloneMetadata();
metadata->name = new_name;
SetItemMetadata(id, std::move(metadata));
}
void AppListTestModel::RequestAppListSort(AppListSortOrder order) {
requested_sort_order_ = order;
}
void AppListTestModel::RequestAppListSortRevert() {
requested_sort_order_.reset();
}
void AppListTestModel::RequestCommitTemporarySortOrder() {
// Committing the temporary sort order should not introduce item reorder so
// reset the sort order without reorder animation.
AppListController::Get()->UpdateAppListWithNewTemporarySortOrder(
/*new_order=*/std::nullopt, /*animate=*/false, base::NullCallback());
}
AppListItem* AppListTestModel::AddItemToFolder(AppListItem* item,
const std::string& folder_id) {
return AppListModel::AddItemToFolder(base::WrapUnique(item), folder_id);
}
void AppListTestModel::MoveItemToFolder(AppListItem* item,
const std::string& folder_id) {
AppListModel::MoveItemToFolder(item, folder_id);
}
// static
std::string AppListTestModel::GetItemName(int id) {
return base::StringPrintf("Item %d", id);
}
void AppListTestModel::PopulateApps(int n) {
for (int i = 0; i < n; ++i) {
CreateAndAddItem(GetItemName(naming_index_++));
}
}
AppListFolderItem* AppListTestModel::CreateAndPopulateFolderWithApps(int n) {
DCHECK_GT(n, 1);
AppListTestItem* item = CreateAndAddItem(GetItemName(naming_index_++));
std::string merged_item_id = item->id();
for (int i = 1; i < n; ++i) {
AppListTestItem* new_item = CreateAndAddItem(GetItemName(naming_index_++));
merged_item_id = AppListModel::MergeItems(merged_item_id, new_item->id());
}
AppListItem* merged_item = FindItem(merged_item_id);
DCHECK(merged_item->GetItemType() == AppListFolderItem::kItemType);
return static_cast<AppListFolderItem*>(merged_item);
}
AppListFolderItem* AppListTestModel::CreateAndAddOemFolder() {
AppListFolderItem* folder = new AppListFolderItem(
ash::kOemFolderId, /*app_list_model_delegate=*/this);
return static_cast<AppListFolderItem*>(AddItem(folder));
}
AppListFolderItem* AppListTestModel::CreateSingleItemFolder(
const std::string& folder_id,
const std::string& item_id) {
AppListTestItem* item = CreateItem(item_id);
AddItemToFolder(item, folder_id);
AppListItem* folder_item = FindItem(folder_id);
DCHECK(folder_item->GetItemType() == AppListFolderItem::kItemType);
return static_cast<AppListFolderItem*>(folder_item);
}
AppListFolderItem* AppListTestModel::CreateSingleWebAppShortcutItemFolder(
const std::string& folder_id,
const std::string& item_id) {
AppListTestItem* item = CreateWebAppShortcutItem(item_id);
AddItemToFolder(item, folder_id);
AppListItem* folder_item = FindItem(folder_id);
DCHECK(folder_item->GetItemType() == AppListFolderItem::kItemType);
return static_cast<AppListFolderItem*>(folder_item);
}
void AppListTestModel::PopulateAppWithId(int id) {
CreateAndAddItem(GetItemName(id));
}
std::string AppListTestModel::GetModelContent() {
std::vector<std::string> ids;
ids.reserve(top_level_item_list()->item_count());
for (size_t i = 0; i < top_level_item_list()->item_count(); ++i)
ids.push_back(top_level_item_list()->item_at(i)->id());
return base::JoinString(ids, ",");
}
syncer::StringOrdinal AppListTestModel::CalculatePosition() {
size_t nitems = top_level_item_list()->item_count();
syncer::StringOrdinal position;
if (nitems == 0) {
position = syncer::StringOrdinal::CreateInitialOrdinal();
} else {
position =
top_level_item_list()->item_at(nitems - 1)->position().CreateAfter();
}
return position;
}
AppListTestModel::AppListTestItem* AppListTestModel::CreateItem(
const std::string& id) {
AppListTestItem* item = new AppListTestItem(id, this);
item->SetPosition(CalculatePosition());
SetItemName(item, id);
return item;
}
AppListTestModel::AppListTestItem* AppListTestModel::CreateWebAppShortcutItem(
const std::string& id) {
AppListTestItem* test_item = new AppListTestItem(id, this);
const int badge_icon_dimension = 48;
const gfx::ImageSkia fake_badge_icon =
CreateImageSkia(badge_icon_dimension, badge_icon_dimension);
test_item->UpdateAppHostBadgeForTesting(fake_badge_icon);
test_item->SetPosition(CalculatePosition());
SetItemName(test_item, id);
return test_item;
}
AppListTestModel::AppListTestItem* AppListTestModel::CreateAndAddItem(
const std::string& id) {
std::unique_ptr<AppListTestItem> test_item(CreateItem(id));
AppListItem* item = AppListModel::AddItem(std::move(test_item));
return static_cast<AppListTestItem*>(item);
}
AppListTestModel::AppListTestItem* AppListTestModel::CreateAndAddPromiseItem(
const std::string& id) {
std::unique_ptr<AppListTestItem> test_item(CreateItem(id));
test_item->UpdateAppStatusForTesting(AppStatus::kPending);
const int icon_dimension = 48;
const gfx::ImageSkia fake_promise_icon =
gfx::ImageSkiaOperations::CreateImageWithRoundRectClip(
icon_dimension, CreateImageSkia(icon_dimension, icon_dimension));
AppListItem* item = AppListModel::AddItem(std::move(test_item));
return static_cast<AppListTestItem*>(item);
}
AppListTestModel::AppListTestItem*
AppListTestModel::CreateAndAddWebAppShortcutItemWithHostBadge(
const std::string& id) {
std::unique_ptr<AppListTestItem> test_item(CreateItem(id));
const int badge_icon_dimension = 48;
const gfx::ImageSkia fake_badge_icon =
gfx::test::CreateImageSkia(badge_icon_dimension, SK_ColorCYAN);
test_item->UpdateAppHostBadgeForTesting(fake_badge_icon);
AppListItem* item = AppListModel::AddItem(std::move(test_item));
SetItemName(item, id);
return static_cast<AppListTestItem*>(item);
}
void AppListTestModel::ItemActivated(AppListTestItem* item) {
last_activated_ = item;
++activate_count_;
}
} // namespace test
} // namespace ash