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_NAMESPACE()20 META_BEGIN_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 no data context given, use this as the data context
135 const auto context = dataContext ? dataContext : interface_pointer_cast<IObject>(owner);
136 if (i->Attaching(owner, context)) {
137 result = Super::Insert(pos, attachment);
138 if (!result) {
139 i->Detaching(owner);
140 }
141 }
142 } else {
143 result = Super::Insert(pos, attachment);
144 }
145 }
146 return result;
147 }
148
Detach(const IObject::Ptr & attachment)149 bool AttachmentContainer::Detach(const IObject::Ptr& attachment)
150 {
151 if (!attachment) {
152 return false;
153 }
154 if (const auto owner = owner_.lock()) {
155 bool res = Super::Remove(attachment);
156 if (res) {
157 if (auto i = interface_pointer_cast<IAttachable>(attachment)) {
158 i->Detaching(owner);
159 }
160 }
161 return res;
162 }
163 return false;
164 }
165
GetAttachments(const BASE_NS::vector<TypeId> & uids,bool strict)166 BASE_NS::vector<IObject::Ptr> AttachmentContainer::GetAttachments(const BASE_NS::vector<TypeId>& uids, bool strict)
167 {
168 return Super::FindAll({ "", TraversalType::NO_HIERARCHY, uids, strict });
169 }
170
RemoveAllAttachments()171 void AttachmentContainer::RemoveAllAttachments()
172 {
173 const auto owner = owner_.lock();
174 const auto all = Super::GetAll();
175 for (const auto& object : all) {
176 if (auto att = interface_cast<IAttachable>(object)) {
177 // Ignore result
178 att->Detaching(owner);
179 }
180 }
181 Super::RemoveAll();
182 }
183
FindByName(const BASE_NS::string & name) const184 IObject::Ptr AttachmentContainer::FindByName(const BASE_NS::string& name) const
185 {
186 return ContainerBase::FindByName(name);
187 }
188
AlreadyAttached(const IObject::Ptr & object)189 bool AttachmentContainer::AlreadyAttached(const IObject::Ptr& object)
190 {
191 if (const auto attachment = interface_pointer_cast<IAttachment>(object)) {
192 if (const auto owner = owner_.lock(); attachment && owner) {
193 if (const auto current = GetValue(attachment->AttachedTo()).lock()) {
194 if (current == owner) {
195 // Already attached to this
196 return true;
197 }
198 }
199 }
200 } else {
201 BASE_NS::shared_ptr<IContainer> self(this, [](auto) {});
202 return META_NS::ContainsObject(self, object);
203 }
204 return false;
205 }
206
207 META_END_NAMESPACE()
208