/* * 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 #include META_BEGIN_NAMESPACE() AttachmentContainer::AttachmentContainer() = default; AttachmentContainer::~AttachmentContainer() { RemoveAllAttachments(); } void AttachmentContainer::SetSuperInstance(const IObject::Ptr& aggr, const IObject::Ptr& super) { Super::SetSuperInstance(aggr, super); transaction_ = interface_cast(super); CORE_ASSERT(transaction_); } bool AttachmentContainer::Build(const IMetadata::Ptr& data) { // Always set null as the parent of all our attachments ObjectContainerFwd::SetProxyParent({}); OnRemoved()->AddHandler(MakeCallback(this, &AttachmentContainer::RemovedFromContainer)); OnAdding()->AddHandler(MakeCallback(this, &AttachmentContainer::AddingToContainer)); return true; } 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; } return ObjectContainerFwd::Replace(child, replaceWith, addAlways); } void AttachmentContainer::RemoveAll() { RemoveAllAttachments(); } bool AttachmentContainer::SetRequiredInterfaces(const BASE_NS::vector& 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::Attach( IContainer::SizeType pos, const IObject::Ptr& attachment, const IObject::Ptr& dataContext) { const auto object = interface_pointer_cast(attachment); if (!object) { return false; } bool result = false; if (const auto owner = owner_.lock()) { // If attachment is attached to something, detach it if (const auto att = interface_cast(attachment)) { if (const auto current = GetValue(att->AttachedTo()).lock()) { if (current == owner) { // Already attached to this return true; } if (!current->Detach(attachment)) { return false; } } } // If no data context given, use this as the data context const auto context = dataContext ? dataContext : interface_pointer_cast(owner); addingContexts_.emplace_back(BASE_NS::pair { attachment.get(), context }); result = ObjectContainerFwd::Insert(pos, object); if (!result) { addingContexts_.pop_back(); } } return result; } bool AttachmentContainer::Detach(const IObject::Ptr& attachment) { if (!attachment) { return false; } if (const auto owner = owner_.lock()) { if (const auto att = interface_cast(attachment)) { const auto current = GetValue(att->AttachedTo()).lock(); if (current != owner) { return false; } } return ObjectContainerFwd::Remove(attachment); } return false; } void AttachmentContainer::AddingToContainer(const ChildChangedInfo& info, bool& success) { if (const auto owner = owner_.lock()) { if (auto object = info.object) { IObject::Ptr context; for (auto it = addingContexts_.begin(); it != addingContexts_.end(); it++) { if (it->first == object.get()) { context = it->second.lock(); addingContexts_.erase(it); break; } } if (auto attachment = interface_pointer_cast(info.object)) { if (GetValue(attachment->AttachedTo()).lock() == owner) { // Already attached to this return; } if (!attachment->Attaching(owner, context)) { success = false; } } else { success = true; } } } } void AttachmentContainer::RemovedFromContainer(const ChildChangedInfo& info) { if (const auto owner = owner_.lock()) { if (auto attachment = interface_pointer_cast(info.object)) { attachment->Detaching(owner); } } } BASE_NS::vector AttachmentContainer::GetAttachments(const BASE_NS::vector& uids, bool strict) { return ObjectContainerFwd::FindAll({ "", TraversalType::NO_HIERARCHY, uids, strict }); } void AttachmentContainer::RemoveAllAttachments() { const auto owner = owner_.lock(); const auto all = ObjectContainerFwd::GetAll(); for (const auto& object : all) { if (auto att = interface_cast(object)) { // Ignore result att->Detaching(owner); } } ObjectContainerFwd::RemoveAll(); } IObject::Ptr AttachmentContainer::FindByName(const BASE_NS::string& name) const { return ObjectContainerFwd::FindByName(name); } bool AttachmentContainer::AlreadyAttached(const IObject::Ptr& object) { if (const auto attachment = interface_pointer_cast(object)) { if (const auto owner = owner_.lock(); attachment && owner) { if (const auto current = GetValue(attachment->AttachedTo()).lock()) { if (current == owner) { // Already attached to this return true; } } } } else { return META_NS::ContainsObject(GetSelf(), object); } return false; } META_END_NAMESPACE()