* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "attachment_container.h"
#include <meta/api/make_callback.h>
#include <meta/api/util.h>
META_BEGIN_INTERNAL_NAMESPACE()
AttachmentContainer::AttachmentContainer()
{
Super::SetImplementingIContainer(nullptr, this);
}
AttachmentContainer::~AttachmentContainer()
{
RemoveAllAttachments();
}
bool AttachmentContainer::Add(const IObject::Ptr& object)
{
return Attach(N_POS, object, {});
}
bool AttachmentContainer::Insert(IContainer::SizeType index, const IObject::Ptr& object)
{
return Attach(index, object, {});
}
bool AttachmentContainer::Remove(IContainer::SizeType index)
{
return Remove(GetAt(index));
}
bool AttachmentContainer::Remove(const IObject::Ptr& child)
{
return Detach(child);
}
bool AttachmentContainer::Replace(const IObject::Ptr& child, const IObject::Ptr& replaceWith, bool addAlways)
{
const auto owner = owner_.lock();
if (child && AlreadyAttached(replaceWith)) {
return true;
}
if (auto i = interface_pointer_cast<IAttachable>(replaceWith)) {
if (!i->Attaching(owner, nullptr)) {
return false;
}
}
bool res = Super::Replace(child, replaceWith, addAlways);
if (res) {
if (auto i = interface_pointer_cast<IAttachable>(child)) {
i->Detaching(owner);
}
} else {
if (auto i = interface_pointer_cast<IAttachable>(replaceWith)) {
i->Detaching(owner);
}
}
return res;
}
void AttachmentContainer::RemoveAll()
{
RemoveAllAttachments();
}
bool AttachmentContainer::SetRequiredInterfaces(const BASE_NS::vector<TypeId>& interfaces)
{
CORE_LOG_E("Setting the required interfaces of an attachment container is not allowed.");
return false;
}
bool AttachmentContainer::Initialize(const META_NS::IAttach::Ptr& owner)
{
if (!owner) {
return false;
}
owner_ = owner;
return true;
}
bool AttachmentContainer::Attach(const IObject::Ptr& attachment, const IObject::Ptr& dataContext)
{
return Attach(N_POS, attachment, dataContext);
}
bool AttachmentContainer::DetachFromOld(const IAttach::Ptr& me, const IObject::Ptr& attachment, bool& mine)
{
if (const auto att = interface_cast<IAttachment>(attachment)) {
if (const auto current = GetValue(att->AttachedTo()).lock()) {
mine = current == me;
if (!mine) {
return current->Detach(attachment);
}
}
}
return true;
}
bool AttachmentContainer::Attach(
IContainer::SizeType pos, const IObject::Ptr& attachment, const IObject::Ptr& dataContext)
{
if (!attachment) {
return false;
}
bool result = false;
if (const auto owner = owner_.lock()) {
bool mine = false;
if (!DetachFromOld(owner, attachment, mine)) {
return false;
}
if (mine) {
return true;
}
if (auto i = interface_pointer_cast<IAttachable>(attachment)) {
if (i->Attaching(owner, dataContext)) {
result = Super::Insert(pos, attachment);
if (!result) {
i->Detaching(owner);
}
}
} else {
result = Super::Insert(pos, attachment);
}
}
return result;
}
bool AttachmentContainer::Detach(const IObject::Ptr& attachment)
{
if (!attachment) {
return false;
}
if (const auto owner = owner_.lock()) {
bool res = Super::Remove(attachment);
if (res) {
if (auto i = interface_pointer_cast<IAttachable>(attachment)) {
i->Detaching(owner);
}
}
return res;
}
return false;
}
BASE_NS::vector<IObject::Ptr> AttachmentContainer::GetAttachments(const BASE_NS::vector<TypeId>& uids, bool strict)
{
return Super::FindAll({"", TraversalType::NO_HIERARCHY, uids, strict});
}
void AttachmentContainer::RemoveAllAttachments()
{
const auto owner = owner_.lock();
const auto all = Super::GetAll();
for (const auto& object : all) {
if (auto att = interface_cast<IAttachable>(object)) {
att->Detaching(owner);
}
}
Super::RemoveAll();
}
IObject::Ptr AttachmentContainer::FindByName(const BASE_NS::string& name) const
{
return ContainerBase::FindByName(name);
}
bool AttachmentContainer::AlreadyAttached(const IObject::Ptr& object)
{
if (const auto attachment = interface_pointer_cast<IAttachment>(object)) {
if (const auto owner = owner_.lock(); attachment && owner) {
if (const auto current = GetValue(attachment->AttachedTo()).lock()) {
if (current == owner) {
return true;
}
}
}
} else {
BASE_NS::shared_ptr<IContainer> self(this, [](auto) {});
return META_NS::ContainsObject(self, object);
}
return false;
}
META_END_INTERNAL_NAMESPACE()