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
16 #include "core/interfaces/native/node/node_adapter_impl.h"
17
18 #include "core/components_ng/syntax/lazy_for_each_node.h"
19
20 struct _ArkUINodeAdapter {
21 OHOS::Ace::RefPtr<OHOS::Ace::NG::NativeLazyForEachBuilder> builder;
22 OHOS::Ace::RefPtr<OHOS::Ace::NG::LazyForEachNode> node;
23 };
24
25 namespace OHOS::Ace::NG {
26
RegisterDataChangeListener(const RefPtr<V2::DataChangeListener> & listener)27 void NativeLazyForEachBuilder::RegisterDataChangeListener(const RefPtr<V2::DataChangeListener>& listener)
28 {
29 listener_ = RawPtr(listener);
30 if (!receiver_) {
31 return;
32 }
33 ArkUINodeAdapterEvent event { .type = ON_ATTACH_TO_NODE };
34 event.extraParam = reinterpret_cast<intptr_t>(userData_);
35 auto lazyForEachNode = DynamicCast<LazyForEachNode>(listener);
36 if (lazyForEachNode) {
37 auto parent = lazyForEachNode->GetParent();
38 if (parent) {
39 event.handle = reinterpret_cast<ArkUINodeHandle>(RawPtr(parent));
40 }
41 }
42 receiver_(&event);
43 }
44
UnregisterDataChangeListener(V2::DataChangeListener * listener)45 void NativeLazyForEachBuilder::UnregisterDataChangeListener(V2::DataChangeListener* listener)
46 {
47 listener_ = nullptr;
48 if (!receiver_) {
49 return;
50 }
51 ArkUINodeAdapterEvent event { .type = ON_DETACH_FROM_NODE };
52 event.extraParam = reinterpret_cast<intptr_t>(userData_);
53 receiver_(&event);
54 }
55
OnGetTotalCount()56 int32_t NativeLazyForEachBuilder::OnGetTotalCount()
57 {
58 return totalCount_;
59 }
60
OnGetChildByIndex(int32_t index,std::unordered_map<std::string,LazyForEachCacheChild> & cachedItems)61 LazyForEachChild NativeLazyForEachBuilder::OnGetChildByIndex(
62 int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cachedItems)
63 {
64 LazyForEachChild child;
65 if (!receiver_) {
66 return child;
67 }
68 ArkUINodeAdapterEvent getIdevent { .index = index, .idSet = false, .type = ON_GET_NODE_ID, .nodeSet = false };
69 getIdevent.extraParam = reinterpret_cast<intptr_t>(userData_);
70 receiver_(&getIdevent);
71 std::string idStr;
72 if (getIdevent.idSet) {
73 idStr = std::to_string(getIdevent.id);
74 } else {
75 idStr = std::to_string(index);
76 }
77 child.first = idStr;
78 const auto& itemIter = cachedItems.find(idStr);
79 if (itemIter != cachedItems.end()) {
80 child.second = itemIter->second.second;
81 cachedItems.erase(itemIter);
82 // For not change C-API receiver
83 if (needUpdateEvent_) {
84 getIdevent.type = ON_UPDATE_NODE;
85 getIdevent.handle = reinterpret_cast<ArkUINodeHandle>(AceType::RawPtr(child.second));
86 if (!getIdevent.idSet) {
87 getIdevent.id = index;
88 }
89 receiver_(&getIdevent);
90 }
91 FlushDirtyPropertyNodes(child.second);
92 return child;
93 }
94 ArkUINodeAdapterEvent getChildEvent {
95 .index = index, .id = getIdevent.id, .idSet = false, .type = ON_ADD_NODE_TO_ADAPTER, .nodeSet = false
96 };
97 getChildEvent.extraParam = reinterpret_cast<intptr_t>(userData_);
98 receiver_(&getChildEvent);
99 if (getChildEvent.nodeSet) {
100 child.second = Claim(reinterpret_cast<UINode*>(getChildEvent.handle));
101 }
102 FlushDirtyPropertyNodes(child.second);
103 return child;
104 }
105
FlushDirtyPropertyNodes(const RefPtr<UINode> & node)106 void NativeLazyForEachBuilder::FlushDirtyPropertyNodes(const RefPtr<UINode>& node)
107 {
108 CHECK_NULL_VOID(node);
109 auto context = node->GetContext();
110 CHECK_NULL_VOID(context);
111 context->FlushDirtyPropertyNodes();
112 }
113
OnItemDeleted(UINode * node,const std::string & key)114 void NativeLazyForEachBuilder::OnItemDeleted(UINode* node, const std::string& key)
115 {
116 if (!receiver_) {
117 return;
118 }
119 ArkUINodeAdapterEvent event {
120 .id = StringUtils::StringToInt(key), .idSet = false, .type = ON_REMOVE_NODE_FROM_ADAPTER, .nodeSet = false
121 };
122 event.extraParam = reinterpret_cast<intptr_t>(userData_);
123 event.handle = reinterpret_cast<ArkUINodeHandle>(node);
124 receiver_(&event);
125 }
126
GetAllItem(ArkUINodeHandle ** items,ArkUI_Uint32 * size)127 ArkUI_Int32 NativeLazyForEachBuilder::GetAllItem(ArkUINodeHandle** items, ArkUI_Uint32* size)
128 {
129 std::vector<UINode*> childList;
130 GetAllItems(childList);
131 *size = childList.size();
132 *items = new ArkUINodeHandle[*size];
133 for (uint32_t i = 0; i < *size; i++) {
134 (*items)[i] = reinterpret_cast<ArkUINodeHandle>(childList[i]);
135 }
136 return ERROR_CODE_NO_ERROR;
137 }
138
UINodeAdapter(ArkUINodeAdapterHandle handle)139 UINodeAdapter::UINodeAdapter(ArkUINodeAdapterHandle handle) : handle_(handle)
140 {
141 CHECK_NULL_VOID(handle_);
142 CHECK_NULL_VOID(handle_->builder);
143 handle_->builder->SetUserData(this);
144 handle_->builder->SetReceiver([](ArkUINodeAdapterEvent* event) {
145 CHECK_NULL_VOID(event);
146 auto adapter = reinterpret_cast<UINodeAdapter*>(event->extraParam);
147 if (adapter != nullptr) {
148 adapter->OnEventReceived(event);
149 }
150 });
151 handle_->builder->SetNeedUpdateEvent(true);
152 }
153
~UINodeAdapter()154 UINodeAdapter::~UINodeAdapter()
155 {
156 if (handle_ != nullptr) {
157 delete handle_;
158 handle_ = nullptr;
159 }
160 }
161
OnEventReceived(ArkUINodeAdapterEvent * event)162 void UINodeAdapter::OnEventReceived(ArkUINodeAdapterEvent* event)
163 {
164 switch (event->type) {
165 case ON_ATTACH_TO_NODE:
166 if (attachToNodeFunc_) {
167 attachToNodeFunc_(event->handle);
168 }
169 break;
170 case ON_DETACH_FROM_NODE:
171 if (detachFromNodeFunc_) {
172 detachFromNodeFunc_();
173 }
174 break;
175 case ON_GET_NODE_ID:
176 if (getChildIdFunc_) {
177 auto id = getChildIdFunc_(event->index);
178 event->idSet = true;
179 event->id = id;
180 }
181 break;
182 case ON_ADD_NODE_TO_ADAPTER:
183 if (createNewChildFunc_) {
184 auto handle = createNewChildFunc_(event->index);
185 event->nodeSet = true;
186 event->handle = handle;
187 }
188 break;
189 case ON_REMOVE_NODE_FROM_ADAPTER:
190 if (disposeChildFunc_) {
191 disposeChildFunc_(event->handle, event->id);
192 }
193 break;
194 case ON_UPDATE_NODE:
195 if (updateChildFunc_) {
196 updateChildFunc_(event->handle, event->id);
197 }
198 break;
199 default:
200 break;
201 }
202 }
203
SetTotalNodeCount(uint32_t count)204 void UINodeAdapter::SetTotalNodeCount(uint32_t count)
205 {
206 CHECK_NULL_VOID(handle_);
207 CHECK_NULL_VOID(handle_->builder);
208 handle_->builder->SetNodeTotalCount(count);
209 }
210
GetTotalNodeCount() const211 uint32_t UINodeAdapter::GetTotalNodeCount() const
212 {
213 CHECK_NULL_RETURN(handle_, 0);
214 CHECK_NULL_RETURN(handle_->builder, 0);
215 return handle_->builder->GetNodeTotalCount();
216 }
217
NotifyItemReloaded()218 void UINodeAdapter::NotifyItemReloaded()
219 {
220 CHECK_NULL_VOID(handle_);
221 CHECK_NULL_VOID(handle_->builder);
222 handle_->builder->NotifyItemReloaded();
223 }
224
NotifyItemChanged(uint32_t start,uint32_t count)225 void UINodeAdapter::NotifyItemChanged(uint32_t start, uint32_t count)
226 {
227 CHECK_NULL_VOID(handle_);
228 CHECK_NULL_VOID(handle_->builder);
229 handle_->builder->NotifyItemChanged(start, count);
230 }
231
NotifyItemInserted(uint32_t start,uint32_t count)232 void UINodeAdapter::NotifyItemInserted(uint32_t start, uint32_t count)
233 {
234 CHECK_NULL_VOID(handle_);
235 CHECK_NULL_VOID(handle_->builder);
236 handle_->builder->NotifyItemInserted(start, count);
237 }
238
NotifyItemMoved(uint32_t from,uint32_t to)239 void UINodeAdapter::NotifyItemMoved(uint32_t from, uint32_t to)
240 {
241 CHECK_NULL_VOID(handle_);
242 CHECK_NULL_VOID(handle_->builder);
243 handle_->builder->NotifyItemMoved(from, to);
244 }
245
NotifyItemRemoved(uint32_t start,uint32_t count)246 void UINodeAdapter::NotifyItemRemoved(uint32_t start, uint32_t count)
247 {
248 CHECK_NULL_VOID(handle_);
249 CHECK_NULL_VOID(handle_->builder);
250 handle_->builder->NotifyItemRemoved(start, count);
251 }
252
GetAllItems()253 std::vector<ArkUINodeHandle> UINodeAdapter::GetAllItems()
254 {
255 std::vector<ArkUINodeHandle> items;
256 CHECK_NULL_RETURN(handle_, items);
257 CHECK_NULL_RETURN(handle_->builder, items);
258
259 ArkUINodeHandle* itemArray = nullptr;
260 uint32_t size = 0;
261 handle_->builder->GetAllItem(&itemArray, &size);
262 for (uint32_t i = 0; i < size; i++) {
263 items.push_back(itemArray[i]);
264 }
265 if (itemArray != nullptr) {
266 delete[] itemArray;
267 }
268 return items;
269 }
270
271 } // namespace OHOS::Ace::NG
272
273 namespace OHOS::Ace::NodeAdapter {
274 namespace {
275
Create()276 ArkUINodeAdapterHandle Create()
277 {
278 auto* adapter = new _ArkUINodeAdapter { .builder = AceType::MakeRefPtr<NG::NativeLazyForEachBuilder>() };
279 adapter->builder->SetHostHandle(adapter);
280 return adapter;
281 }
282
Dispose(ArkUINodeAdapterHandle handle)283 void Dispose(ArkUINodeAdapterHandle handle)
284 {
285 if (!handle) {
286 return;
287 }
288 if (handle->node) {
289 const auto& parent = handle->node->GetParent();
290 if (parent) {
291 parent->RemoveChild(handle->node);
292 }
293 }
294 if (handle->builder) {
295 handle->builder->SetHostHandle(nullptr);
296 }
297 delete handle;
298 }
299
SetTotalNodeCount(ArkUINodeAdapterHandle handle,ArkUI_Uint32 size)300 ArkUI_Int32 SetTotalNodeCount(ArkUINodeAdapterHandle handle, ArkUI_Uint32 size)
301 {
302 if (handle) {
303 handle->builder->SetNodeTotalCount(size);
304 return ERROR_CODE_NO_ERROR;
305 }
306 return ERROR_CODE_PARAM_INVALID;
307 }
308
GetTotalNodeCount(ArkUINodeAdapterHandle handle)309 ArkUI_Uint32 GetTotalNodeCount(ArkUINodeAdapterHandle handle)
310 {
311 if (handle) {
312 return handle->builder->GetNodeTotalCount();
313 }
314 return 0;
315 }
316
RegisterEventReceiver(ArkUINodeAdapterHandle handle,void * userData,void (* receiver)(ArkUINodeAdapterEvent * event))317 ArkUI_Int32 RegisterEventReceiver(
318 ArkUINodeAdapterHandle handle, void* userData, void (*receiver)(ArkUINodeAdapterEvent* event))
319 {
320 if (!handle) {
321 return ERROR_CODE_PARAM_INVALID;
322 }
323 handle->builder->SetUserData(userData);
324 handle->builder->SetReceiver(receiver);
325 return ERROR_CODE_NO_ERROR;
326 }
327
UnregisterEventReceiver(ArkUINodeAdapterHandle handle)328 void UnregisterEventReceiver(ArkUINodeAdapterHandle handle)
329 {
330 if (!handle) {
331 return;
332 }
333 handle->builder->SetUserData(nullptr);
334 handle->builder->SetReceiver(nullptr);
335 }
336
NotifyItemReloaded(ArkUINodeAdapterHandle handle)337 ArkUI_Int32 NotifyItemReloaded(ArkUINodeAdapterHandle handle)
338 {
339 if (!handle) {
340 return ERROR_CODE_PARAM_INVALID;
341 }
342 return handle->builder->NotifyItemReloaded();
343 }
344
NotifyItemChanged(ArkUINodeAdapterHandle handle,ArkUI_Uint32 startPosition,ArkUI_Uint32 itemCount)345 ArkUI_Int32 NotifyItemChanged(ArkUINodeAdapterHandle handle, ArkUI_Uint32 startPosition, ArkUI_Uint32 itemCount)
346 {
347 if (!handle) {
348 return ERROR_CODE_PARAM_INVALID;
349 }
350 return handle->builder->NotifyItemChanged(startPosition, itemCount);
351 }
352
NotifyItemRemoved(ArkUINodeAdapterHandle handle,ArkUI_Uint32 startPosition,ArkUI_Uint32 itemCount)353 ArkUI_Int32 NotifyItemRemoved(ArkUINodeAdapterHandle handle, ArkUI_Uint32 startPosition, ArkUI_Uint32 itemCount)
354 {
355 if (!handle) {
356 return ERROR_CODE_PARAM_INVALID;
357 }
358 return handle->builder->NotifyItemRemoved(startPosition, itemCount);
359 }
360
NotifyItemInserted(ArkUINodeAdapterHandle handle,ArkUI_Uint32 startPosition,ArkUI_Uint32 itemCount)361 ArkUI_Int32 NotifyItemInserted(ArkUINodeAdapterHandle handle, ArkUI_Uint32 startPosition, ArkUI_Uint32 itemCount)
362 {
363 if (!handle) {
364 return ERROR_CODE_PARAM_INVALID;
365 }
366 return handle->builder->NotifyItemInserted(startPosition, itemCount);
367 }
368
NotifyItemMoved(ArkUINodeAdapterHandle handle,ArkUI_Uint32 from,ArkUI_Uint32 to)369 ArkUI_Int32 NotifyItemMoved(ArkUINodeAdapterHandle handle, ArkUI_Uint32 from, ArkUI_Uint32 to)
370 {
371 if (!handle) {
372 return ERROR_CODE_PARAM_INVALID;
373 }
374 return handle->builder->NotifyItemMoved(from, to);
375 }
376
GetAllItem(ArkUINodeAdapterHandle handle,ArkUINodeHandle ** items,ArkUI_Uint32 * size)377 ArkUI_Int32 GetAllItem(ArkUINodeAdapterHandle handle, ArkUINodeHandle** items, ArkUI_Uint32* size)
378 {
379 if (!handle) {
380 return ERROR_CODE_PARAM_INVALID;
381 }
382 return handle->builder->GetAllItem(items, size);
383 }
384
GetLazyForEachChildIndex(const RefPtr<NG::UINode> & node)385 int32_t GetLazyForEachChildIndex(const RefPtr<NG::UINode>& node)
386 {
387 int32_t index = 0;
388 for (const auto& iter : node->GetChildren()) {
389 if (AceType::InstanceOf<NG::LazyForEachNode>(iter)) {
390 return index;
391 }
392 index++;
393 }
394 return -1;
395 }
396
AttachHostNode(ArkUINodeAdapterHandle handle,ArkUINodeHandle host)397 ArkUI_Bool AttachHostNode(ArkUINodeAdapterHandle handle, ArkUINodeHandle host)
398 {
399 CHECK_NULL_RETURN(handle, true);
400 CHECK_NULL_RETURN(host, true);
401 auto* uiNode = reinterpret_cast<NG::UINode*>(host);
402 // A NodeAdapter only allows binding to one LazyForEach
403 if (GetLazyForEachChildIndex(Referenced::Claim(uiNode)) != -1) {
404 return false;
405 }
406 if (!handle->node) {
407 handle->node =
408 NG::LazyForEachNode::CreateLazyForEachNode(ElementRegister::GetInstance()->MakeUniqueId(), handle->builder);
409 }
410 if (AceType::InstanceOf<NG::FrameNode>(uiNode)) {
411 auto* frameNode = reinterpret_cast<NG::FrameNode*>(uiNode);
412 if (frameNode->GetPattern()->OnAttachAdapter(Referenced::Claim(frameNode), handle->node)) {
413 return true;
414 } else if (frameNode->GetFirstChild() == nullptr) {
415 uiNode->AddChild(handle->node);
416 return true;
417 }
418 }
419 return false;
420 }
421
DetachHostNode(ArkUINodeHandle host)422 void DetachHostNode(ArkUINodeHandle host)
423 {
424 CHECK_NULL_VOID(host);
425 auto* uiNode = reinterpret_cast<NG::UINode*>(host);
426 if (!AceType::InstanceOf<NG::FrameNode>(uiNode)) {
427 return;
428 }
429 auto* frameNode = reinterpret_cast<NG::FrameNode*>(uiNode);
430 // Component overload unbinding method, unbind LazyForEach according to your own specifications
431 if (frameNode->GetPattern()->DetachHostNodeAdapter(Referenced::Claim(frameNode))) {
432 return;
433 }
434 int32_t index = 0;
435 // The default first node is LazyForEach. If the LazyForEach node is not unbound
436 if (!AceType::InstanceOf<NG::LazyForEachNode>(uiNode->GetChildAtIndex(0))) {
437 index = GetLazyForEachChildIndex(Referenced::Claim(uiNode));
438 }
439 if (index == -1) {
440 return;
441 }
442 const auto& child = AceType::DynamicCast<NG::LazyForEachNode>(uiNode->GetChildAtIndex(index));
443 CHECK_NULL_VOID(child);
444 uiNode->RemoveChild(child);
445 const auto& builder = AceType::DynamicCast<NG::NativeLazyForEachBuilder>(child->GetBuilder());
446 CHECK_NULL_VOID(builder);
447 auto handle = builder->GetHostHandle();
448 CHECK_NULL_VOID(handle);
449 handle->node = nullptr;
450 }
451
GetNodeAdapter(ArkUINodeHandle host)452 ArkUINodeAdapterHandle GetNodeAdapter(ArkUINodeHandle host)
453 {
454 CHECK_NULL_RETURN(host, nullptr);
455 auto* uiNode = reinterpret_cast<NG::UINode*>(host);
456 if (!AceType::InstanceOf<NG::FrameNode>(uiNode)) {
457 return nullptr;
458 }
459 ArkUINodeAdapterHandle handle = nullptr;
460 auto* frameNode = reinterpret_cast<NG::FrameNode*>(uiNode);
461 if (frameNode->GetPattern()->GetNodeAdapterComponent(handle, Referenced::Claim(frameNode))) {
462 return handle;
463 }
464 int32_t index = 0;
465 // The default first node is LazyForEach. If the LazyForEach node is not unbound
466 if (!AceType::InstanceOf<NG::LazyForEachNode>(uiNode->GetChildAtIndex(0))) {
467 index = GetLazyForEachChildIndex(Referenced::Claim(uiNode));
468 }
469 if (index == -1) {
470 return nullptr;
471 }
472 const auto& child = AceType::DynamicCast<NG::LazyForEachNode>(uiNode->GetChildAtIndex(index));
473 CHECK_NULL_RETURN(child, nullptr);
474 const auto& builder = AceType::DynamicCast<NG::NativeLazyForEachBuilder>(child->GetBuilder());
475 CHECK_NULL_RETURN(builder, nullptr);
476 return builder->GetHostHandle();
477 }
478
GetNodeTypeInNodeAdapter(ArkUINodeAdapterHandle handle)479 ArkUI_CharPtr GetNodeTypeInNodeAdapter(ArkUINodeAdapterHandle handle)
480 {
481 CHECK_NULL_RETURN(handle, "");
482 CHECK_NULL_RETURN(handle->node, "");
483 static std::string nodeType = handle->node->GetTag();
484 return nodeType.c_str();
485 }
486
FireArkUIObjectLifecycleCallback(void * data,ArkUINodeAdapterHandle handle)487 void FireArkUIObjectLifecycleCallback(void* data, ArkUINodeAdapterHandle handle)
488 {
489 CHECK_NULL_VOID(data);
490 CHECK_NULL_VOID(handle);
491 CHECK_NULL_VOID(handle->node);
492 auto context = handle->node->GetContext();
493 CHECK_NULL_VOID(context);
494 context->FireArkUIObjectLifecycleCallback(data);
495 }
496 } // namespace
497
GetNodeAdapterAPI()498 const ArkUINodeAdapterAPI* GetNodeAdapterAPI()
499 {
500 CHECK_INITIALIZED_FIELDS_BEGIN(); // don't move this line
501 static const ArkUINodeAdapterAPI impl {
502 .create = Create,
503 .dispose = Dispose,
504 .setTotalNodeCount = SetTotalNodeCount,
505 .getTotalNodeCount = GetTotalNodeCount,
506 .registerEventReceiver = RegisterEventReceiver,
507 .unregisterEventReceiver = UnregisterEventReceiver,
508 .notifyItemReloaded = NotifyItemReloaded,
509 .notifyItemChanged = NotifyItemChanged,
510 .notifyItemRemoved = NotifyItemRemoved,
511 .notifyItemInserted = NotifyItemInserted,
512 .notifyItemMoved = NotifyItemMoved,
513 .getAllItem = GetAllItem,
514 .attachHostNode = AttachHostNode,
515 .detachHostNode = DetachHostNode,
516 .getNodeAdapter = GetNodeAdapter,
517 .getNodeType = GetNodeTypeInNodeAdapter,
518 .fireArkUIObjectLifecycleCallback = FireArkUIObjectLifecycleCallback
519 };
520 CHECK_INITIALIZED_FIELDS_END(impl, 0, 0, 0); // don't move this line
521 return &impl;
522 }
523
GetCJUINodeAdapterAPI()524 const CJUINodeAdapterAPI* GetCJUINodeAdapterAPI()
525 {
526 CHECK_INITIALIZED_FIELDS_BEGIN(); // don't move this line
527 static const CJUINodeAdapterAPI impl {
528 .create = Create,
529 .dispose = Dispose,
530 .setTotalNodeCount = SetTotalNodeCount,
531 .getTotalNodeCount = GetTotalNodeCount,
532 .registerEventReceiver = RegisterEventReceiver,
533 .unregisterEventReceiver = UnregisterEventReceiver,
534 .notifyItemReloaded = NotifyItemReloaded,
535 .notifyItemChanged = NotifyItemChanged,
536 .notifyItemRemoved = NotifyItemRemoved,
537 .notifyItemInserted = NotifyItemInserted,
538 .notifyItemMoved = NotifyItemMoved,
539 .getAllItem = GetAllItem,
540 .attachHostNode = AttachHostNode,
541 .detachHostNode = DetachHostNode,
542 .getNodeAdapter = GetNodeAdapter
543 };
544 CHECK_INITIALIZED_FIELDS_END(impl, 0, 0, 0); // don't move this line
545 return &impl;
546 }
547
548 } // namespace OHOS::Ace::NodeAdapter
549