blob: 9fe48aaf61d190d73d26fccd1d5d8453d3544d16 [file] [log] [blame]
// Copyright 2020 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 "ash/public/cpp/holding_space/holding_space_model.h"
#include <algorithm>
#include "ash/public/cpp/holding_space/holding_space_model_observer.h"
#include "base/bind.h"
#include "base/check.h"
#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
namespace ash {
// HoldingSpaceModel::ScopedItemUpdate -----------------------------------------
HoldingSpaceModel::ScopedItemUpdate::~ScopedItemUpdate() {
bool did_update = false;
// Update backing file.
if (file_path_ && file_system_url_) {
did_update |=
item_->SetBackingFile(file_path_.value(), file_system_url_.value());
}
// Update pause.
if (paused_)
did_update |= item_->SetPaused(paused_.value());
// Update progress.
if (progress_)
did_update |= item_->SetProgress(progress_.value());
// Update current size.
if (current_size_in_bytes_)
did_update |= item_->SetCurrentSizeInBytes(current_size_in_bytes_.value());
// Notify observers if and only if an update occurred.
if (did_update) {
for (auto& observer : model_->observers_)
observer.OnHoldingSpaceItemUpdated(item_);
}
}
HoldingSpaceModel::ScopedItemUpdate&
HoldingSpaceModel::ScopedItemUpdate::SetBackingFile(
const base::FilePath& file_path,
const GURL& file_system_url) {
file_path_ = file_path;
file_system_url_ = file_system_url;
return *this;
}
HoldingSpaceModel::ScopedItemUpdate&
HoldingSpaceModel::ScopedItemUpdate::SetPaused(bool paused) {
paused_ = paused;
return *this;
}
HoldingSpaceModel::ScopedItemUpdate&
HoldingSpaceModel::ScopedItemUpdate::SetProgress(
const absl::optional<float>& progress) {
progress_ = progress;
return *this;
}
HoldingSpaceModel::ScopedItemUpdate&
HoldingSpaceModel::ScopedItemUpdate::SetCurrentSizeInBytes(
const absl::optional<int64_t>& current_size_in_bytes) {
DCHECK(!current_size_in_bytes || current_size_in_bytes >= 0);
current_size_in_bytes_ = current_size_in_bytes;
return *this;
}
HoldingSpaceModel::ScopedItemUpdate::ScopedItemUpdate(HoldingSpaceModel* model,
HoldingSpaceItem* item)
: model_(model), item_(item) {
DCHECK(model_);
DCHECK(item_);
}
// HoldingSpaceModel -----------------------------------------------------------
HoldingSpaceModel::HoldingSpaceModel() = default;
HoldingSpaceModel::~HoldingSpaceModel() = default;
void HoldingSpaceModel::AddItem(std::unique_ptr<HoldingSpaceItem> item) {
std::vector<std::unique_ptr<HoldingSpaceItem>> items;
items.push_back(std::move(item));
AddItems(std::move(items));
}
void HoldingSpaceModel::AddItems(
std::vector<std::unique_ptr<HoldingSpaceItem>> items) {
DCHECK(!items.empty());
std::vector<const HoldingSpaceItem*> item_ptrs;
for (std::unique_ptr<HoldingSpaceItem>& item : items) {
DCHECK(!GetItem(item->id()));
if (item->IsInitialized())
++initialized_item_counts_by_type_[item->type()];
item_ptrs.push_back(item.get());
items_.push_back(std::move(item));
}
for (auto& observer : observers_)
observer.OnHoldingSpaceItemsAdded(item_ptrs);
}
void HoldingSpaceModel::RemoveItem(const std::string& id) {
RemoveItems({id});
}
void HoldingSpaceModel::RemoveItems(const std::set<std::string>& item_ids) {
RemoveIf(base::BindRepeating(
[](const std::set<std::string>& item_ids, const HoldingSpaceItem* item) {
return base::Contains(item_ids, item->id());
},
std::cref(item_ids)));
}
void HoldingSpaceModel::InitializeOrRemoveItem(const std::string& id,
const GURL& file_system_url) {
if (file_system_url.is_empty()) {
RemoveItem(id);
return;
}
auto item_it = std::find_if(
items_.begin(), items_.end(),
[&id](const std::unique_ptr<HoldingSpaceItem>& item) -> bool {
return id == item->id();
});
DCHECK(item_it != items_.end());
HoldingSpaceItem* item = item_it->get();
DCHECK(!item->IsInitialized());
item->Initialize(file_system_url);
++initialized_item_counts_by_type_[item->type()];
for (auto& observer : observers_)
observer.OnHoldingSpaceItemInitialized(item);
}
std::unique_ptr<HoldingSpaceModel::ScopedItemUpdate>
HoldingSpaceModel::UpdateItem(const std::string& id) {
auto item_it =
std::find_if(items_.begin(), items_.end(),
[&id](const std::unique_ptr<HoldingSpaceItem>& item) {
return item->id() == id;
});
DCHECK(item_it != items_.end());
return base::WrapUnique(new ScopedItemUpdate(this, item_it->get()));
}
void HoldingSpaceModel::RemoveIf(Predicate predicate) {
// Keep removed items around until `observers_` have been notified of removal.
std::vector<std::unique_ptr<HoldingSpaceItem>> items;
std::vector<const HoldingSpaceItem*> item_ptrs;
for (int i = items_.size() - 1; i >= 0; --i) {
std::unique_ptr<HoldingSpaceItem>& item = items_.at(i);
if (predicate.Run(item.get())) {
item_ptrs.push_back(item.get());
items.push_back(std::move(item));
items_.erase(items_.begin() + i);
if (item_ptrs.back()->IsInitialized())
--initialized_item_counts_by_type_[item_ptrs.back()->type()];
}
}
DCHECK_EQ(items.size(), item_ptrs.size());
if (!items.empty()) {
for (auto& observer : observers_)
observer.OnHoldingSpaceItemsRemoved(item_ptrs);
}
}
void HoldingSpaceModel::InvalidateItemImageIf(Predicate predicate) {
for (auto& item : items_) {
if (predicate.Run(item.get()))
item->InvalidateImage();
}
}
void HoldingSpaceModel::RemoveAll() {
// Clear the item list, but keep the items around until the observers have
// been notified of the item removal.
ItemList items;
items.swap(items_);
initialized_item_counts_by_type_.clear();
std::vector<const HoldingSpaceItem*> item_ptrs;
for (auto& item : items)
item_ptrs.push_back(item.get());
for (auto& observer : observers_)
observer.OnHoldingSpaceItemsRemoved(item_ptrs);
}
const HoldingSpaceItem* HoldingSpaceModel::GetItem(
const std::string& id) const {
auto item_it = std::find_if(
items_.begin(), items_.end(),
[&id](const std::unique_ptr<HoldingSpaceItem>& item) -> bool {
return item->id() == id;
});
if (item_it == items_.end())
return nullptr;
return item_it->get();
}
const HoldingSpaceItem* HoldingSpaceModel::GetItem(
HoldingSpaceItem::Type type,
const base::FilePath& file_path) const {
auto item_it = std::find_if(
items_.begin(), items_.end(),
[&type, &file_path](const std::unique_ptr<HoldingSpaceItem>& item) {
return item->type() == type && item->file_path() == file_path;
});
if (item_it == items_.end())
return nullptr;
return item_it->get();
}
bool HoldingSpaceModel::ContainsItem(HoldingSpaceItem::Type type,
const base::FilePath& file_path) const {
return GetItem(type, file_path) != nullptr;
}
bool HoldingSpaceModel::ContainsInitializedItemOfType(
HoldingSpaceItem::Type type) const {
auto it = initialized_item_counts_by_type_.find(type);
return it != initialized_item_counts_by_type_.end() && it->second > 0u;
}
void HoldingSpaceModel::AddObserver(HoldingSpaceModelObserver* observer) {
observers_.AddObserver(observer);
}
void HoldingSpaceModel::RemoveObserver(HoldingSpaceModelObserver* observer) {
observers_.RemoveObserver(observer);
}
} // namespace ash