1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "attachment_container.h"
16
17 #include <meta/api/make_callback.h>
18 #include <meta/api/util.h>
19
META_BEGIN_INTERNAL_NAMESPACE()20 META_BEGIN_INTERNAL_NAMESPACE()
21
22 AttachmentContainer::AttachmentContainer()
23 {
24 Super::SetImplementingIContainer(nullptr, this);
25 }
26
~AttachmentContainer()27 AttachmentContainer::~AttachmentContainer()
28 {
29 RemoveAllAttachments();
30 }
31
Add(const IObject::Ptr & object)32 bool AttachmentContainer::Add(const IObject::Ptr& object)
33 {
34 return Attach(N_POS, object, {});
35 }
36
Insert(IContainer::SizeType index,const IObject::Ptr & object)37 bool AttachmentContainer::Insert(IContainer::SizeType index, const IObject::Ptr& object)
38 {
39 return Attach(index, object, {});
40 }
41
Remove(IContainer::SizeType index)42 bool AttachmentContainer::Remove(IContainer::SizeType index)
43 {
44 return Remove(GetAt(index));
45 }
46
Remove(const IObject::Ptr & child)47 bool AttachmentContainer::Remove(const IObject::Ptr& child)
48 {
49 return Detach(child);
50 }
51
Replace(const IObject::Ptr & child,const IObject::Ptr & replaceWith,bool addAlways)52 bool AttachmentContainer::Replace(const IObject::Ptr& child, const IObject::Ptr& replaceWith, bool addAlways)
53 {
54 const auto owner = owner_.lock();
55 if (child && AlreadyAttached(replaceWith)) {
56 return true;
57 }
58
59 if (auto i = interface_pointer_cast<IAttachable>(replaceWith)) {
60 if (!i->Attaching(owner, nullptr)) {
61 return false;
62 }
63 }
64
65 bool res = Super::Replace(child, replaceWith, addAlways);
66 if (res) {
67 if (auto i = interface_pointer_cast<IAttachable>(child)) {
68 i->Detaching(owner);
69 }
70 } else {
71 if (auto i = interface_pointer_cast<IAttachable>(replaceWith)) {
72 i->Detaching(owner);
73 }
74 }
75 return res;
76 }
77
RemoveAll()78 void AttachmentContainer::RemoveAll()
79 {
80 RemoveAllAttachments();
81 }
82
SetRequiredInterfaces(const BASE_NS::vector<TypeId> & interfaces)83 bool AttachmentContainer::SetRequiredInterfaces(const BASE_NS::vector<TypeId>& interfaces)
84 {
85 CORE_LOG_E("Setting the required interfaces of an attachment container is not allowed.");
86 return false;
87 }
88
Initialize(const META_NS::IAttach::Ptr & owner)89 bool AttachmentContainer::Initialize(const META_NS::IAttach::Ptr& owner)
90 {
91 if (!owner) {
92 return false;
93 }
94 owner_ = owner;
95 return true;
96 }
97
Attach(const IObject::Ptr & attachment,const IObject::Ptr & dataContext)98 bool AttachmentContainer::Attach(const IObject::Ptr& attachment, const IObject::Ptr& dataContext)
99 {
100 return Attach(N_POS, attachment, dataContext);
101 }
102
DetachFromOld(const IAttach::Ptr & me,const IObject::Ptr & attachment,bool & mine)103 bool AttachmentContainer::DetachFromOld(const IAttach::Ptr& me, const IObject::Ptr& attachment, bool& mine)
104 {
105 // If attachment is attached to something, detach it
106 if (const auto att = interface_cast<IAttachment>(attachment)) {
107 if (const auto current = GetValue(att->AttachedTo()).lock()) {
108 mine = current == me;
109 if (!mine) {
110 return current->Detach(attachment);
111 }
112 }
113 }
114 return true;
115 }
116
Attach(IContainer::SizeType pos,const IObject::Ptr & attachment,const IObject::Ptr & dataContext)117 bool AttachmentContainer::Attach(
118 IContainer::SizeType pos, const IObject::Ptr& attachment, const IObject::Ptr& dataContext)
119 {
120 if (!attachment) {
121 return false;
122 }
123 bool result = false;
124 if (const auto owner = owner_.lock()) {
125 // If attachment is attached to something, detach it
126 bool mine = false;
127 if (!DetachFromOld(owner, attachment, mine)) {
128 return false;
129 }
130 if (mine) {
131 return true;
132 }
133 if (auto i = interface_pointer_cast<IAttachable>(attachment)) {
134 if (i->Attaching(owner, dataContext)) {
135 result = Super::Insert(pos, attachment);
136 if (!result) {
137 i->Detaching(owner);
138 }
139 }
140 } else {
141 result = Super::Insert(pos, attachment);
142 }
143 }
144 return result;
145 }
146
Detach(const IObject::Ptr & attachment)147 bool AttachmentContainer::Detach(const IObject::Ptr& attachment)
148 {
149 if (!attachment) {
150 return false;
151 }
152 if (const auto owner = owner_.lock()) {
153 bool res = Super::Remove(attachment);
154 if (res) {
155 if (auto i = interface_pointer_cast<IAttachable>(attachment)) {
156 i->Detaching(owner);
157 }
158 }
159 return res;
160 }
161 return false;
162 }
163
GetAttachments(const BASE_NS::vector<TypeId> & uids,bool strict)164 BASE_NS::vector<IObject::Ptr> AttachmentContainer::GetAttachments(const BASE_NS::vector<TypeId>& uids, bool strict)
165 {
166 return Super::FindAll({ "", TraversalType::NO_HIERARCHY, uids, strict });
167 }
168
RemoveAllAttachments()169 void AttachmentContainer::RemoveAllAttachments()
170 {
171 const auto owner = owner_.lock();
172 const auto all = Super::GetAll();
173 for (const auto& object : all) {
174 if (auto att = interface_cast<IAttachable>(object)) {
175 // Ignore result
176 att->Detaching(owner);
177 }
178 }
179 Super::RemoveAll();
180 }
181
FindByName(const BASE_NS::string & name) const182 IObject::Ptr AttachmentContainer::FindByName(const BASE_NS::string& name) const
183 {
184 return ContainerBase::FindByName(name);
185 }
186
AlreadyAttached(const IObject::Ptr & object)187 bool AttachmentContainer::AlreadyAttached(const IObject::Ptr& object)
188 {
189 if (const auto attachment = interface_pointer_cast<IAttachment>(object)) {
190 if (const auto owner = owner_.lock(); attachment && owner) {
191 if (const auto current = GetValue(attachment->AttachedTo()).lock()) {
192 if (current == owner) {
193 // Already attached to this
194 return true;
195 }
196 }
197 }
198 } else {
199 BASE_NS::shared_ptr<IContainer> self(this, [](auto) {});
200 return META_NS::ContainsObject(self, object);
201 }
202 return false;
203 }
204
205 META_END_INTERNAL_NAMESPACE()
206