1 /*
2 * Copyright (c) 2022 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/components_ng/syntax/lazy_for_each_node.h"
17
18 #include <utility>
19
20 #include "base/log/ace_trace.h"
21 #include "base/log/dump_log.h"
22 #include "base/memory/referenced.h"
23 #include "base/utils/time_util.h"
24 #include "base/utils/utils.h"
25 #include "core/components_ng/base/view_stack_processor.h"
26 #include "core/components_ng/pattern/list/list_item_pattern.h"
27 #include "core/components_ng/property/property.h"
28 #include "core/components_ng/syntax/lazy_layout_wrapper_builder.h"
29 #include "core/components_v2/inspector/inspector_constants.h"
30 #include "core/pipeline/base/element_register.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32
33 namespace OHOS::Ace::NG {
34
GetOrCreateLazyForEachNode(int32_t nodeId,const RefPtr<LazyForEachBuilder> & forEachBuilder)35 RefPtr<LazyForEachNode> LazyForEachNode::GetOrCreateLazyForEachNode(
36 int32_t nodeId, const RefPtr<LazyForEachBuilder>& forEachBuilder)
37 {
38 auto node = ElementRegister::GetInstance()->GetSpecificItemById<LazyForEachNode>(nodeId);
39 if (node) {
40 if (node->builder_ != forEachBuilder) {
41 TAG_LOGI(AceLogTag::ACE_LAZY_FOREACH, "replace old lazy for each builder");
42 node->builder_ = forEachBuilder;
43 }
44 return node;
45 }
46 node = MakeRefPtr<LazyForEachNode>(nodeId, forEachBuilder);
47 ElementRegister::GetInstance()->AddUINode(node);
48 node->RegisterBuilderListener();
49 return node;
50 }
51
CreateLazyForEachNode(int32_t nodeId,const RefPtr<LazyForEachBuilder> & forEachBuilder)52 RefPtr<LazyForEachNode> LazyForEachNode::CreateLazyForEachNode(
53 int32_t nodeId, const RefPtr<LazyForEachBuilder>& forEachBuilder)
54 {
55 auto node = MakeRefPtr<LazyForEachNode>(nodeId, forEachBuilder);
56 ElementRegister::GetInstance()->AddUINode(node);
57 return node;
58 }
59
AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode> & parent,bool forceMeasure,bool forceLayout)60 void LazyForEachNode::AdjustLayoutWrapperTree(
61 const RefPtr<LayoutWrapperNode>& parent, bool forceMeasure, bool forceLayout)
62 {
63 CHECK_NULL_VOID(builder_);
64 auto lazyLayoutWrapperBuilder = MakeRefPtr<LazyLayoutWrapperBuilder>(builder_, WeakClaim(this));
65 if (parent->GetHostTag() == V2::SWIPER_ETS_TAG) {
66 lazyLayoutWrapperBuilder->SetLazySwiper();
67 }
68 lazyLayoutWrapperBuilder->UpdateForceFlag(forceMeasure, forceLayout);
69 parent->SetLayoutWrapperBuilder(lazyLayoutWrapperBuilder);
70 }
71
BuildAllChildren()72 void LazyForEachNode::BuildAllChildren()
73 {
74 for (int i = 0; i < FrameCount(); i++) {
75 GetFrameChildByIndex(i, true);
76 }
77 tempChildren_.clear();
78 tempChildren_.swap(children_);
79 auto items = builder_->GetAllChildren();
80 for (auto& [index, item] : items) {
81 if (item.second) {
82 RemoveDisappearingChild(item.second);
83 children_.push_back(item.second);
84 }
85 }
86 }
87
PostIdleTask()88 void LazyForEachNode::PostIdleTask()
89 {
90 if (needPredict_) {
91 return;
92 }
93 needPredict_ = true;
94 auto context = GetContext();
95 CHECK_NULL_VOID(context);
96 context->AddPredictTask([weak = AceType::WeakClaim(this)](int64_t deadline, bool canUseLongPredictTask) {
97 ACE_SCOPED_TRACE("LazyForEach predict");
98 auto node = weak.Upgrade();
99 CHECK_NULL_VOID(node);
100 node->needPredict_ = false;
101 auto canRunLongPredictTask = node->requestLongPredict_ && canUseLongPredictTask;
102 if (node->builder_) {
103 node->GetChildren();
104 auto preBuildResult = node->builder_->PreBuild(deadline, node->itemConstraint_, canRunLongPredictTask);
105 if (!preBuildResult) {
106 node->PostIdleTask();
107 } else {
108 node->requestLongPredict_ = true;
109 node->itemConstraint_.reset();
110 }
111 }
112 });
113 }
114
OnDataReloaded()115 void LazyForEachNode::OnDataReloaded()
116 {
117 ACE_SCOPED_TRACE("LazyForEach OnDataReloaded");
118 tempChildren_.clear();
119 tempChildren_.swap(children_);
120 if (builder_) {
121 builder_->SetUseNewInterface(false);
122 builder_->OnDataReloaded();
123 if (FrameCount() == 0) {
124 PostIdleTask();
125 }
126 }
127 NotifyChangeWithCount(0, 0, NotificationType::START_CHANGE_POSITION);
128 if (builder_) {
129 int32_t endChangePos = std::max(builder_->GetHistoryTotalCount(), FrameCount());
130 NotifyChangeWithCount(endChangePos, 0, NotificationType::END_CHANGE_POSITION);
131 }
132 MarkNeedSyncRenderTree(true);
133 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
134 }
135
OnDataAdded(size_t index)136 void LazyForEachNode::OnDataAdded(size_t index)
137 {
138 ACE_SCOPED_TRACE("LazyForEach OnDataAdded");
139 auto insertIndex = static_cast<int32_t>(index);
140 if (builder_) {
141 builder_->SetUseNewInterface(false);
142 builder_->OnDataAdded(index);
143 }
144 tempChildren_.clear();
145 tempChildren_.swap(children_);
146 NotifyChangeWithCount(insertIndex, 1, NotificationType::START_AND_END_CHANGE_POSITION);
147 MarkNeedSyncRenderTree(true);
148 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
149 }
150
OnDataBulkAdded(size_t index,size_t count)151 void LazyForEachNode::OnDataBulkAdded(size_t index, size_t count)
152 {
153 ACE_SCOPED_TRACE("LazyForEach OnDataBulkAdded");
154 auto insertIndex = static_cast<int32_t>(index);
155 if (builder_) {
156 builder_->SetUseNewInterface(false);
157 builder_->OnDataBulkAdded(index, count);
158 }
159 tempChildren_.clear();
160 tempChildren_.swap(children_);
161 NotifyChangeWithCount(insertIndex, static_cast<int32_t>(count), NotificationType::START_AND_END_CHANGE_POSITION);
162 MarkNeedSyncRenderTree(true);
163 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
164 }
165
OnDataDeleted(size_t index)166 void LazyForEachNode::OnDataDeleted(size_t index)
167 {
168 ACE_SCOPED_TRACE("LazyForEach OnDataDeleted");
169 auto deletedIndex = static_cast<int32_t>(index);
170 if (builder_) {
171 builder_->SetUseNewInterface(false);
172 auto node = builder_->OnDataDeleted(index);
173
174 if (node) {
175 if (!node->OnRemoveFromParent(true)) {
176 AddDisappearingChild(node);
177 } else {
178 node->DetachFromMainTree();
179 }
180 builder_->ProcessOffscreenNode(node, true);
181 }
182 }
183 tempChildren_.clear();
184 tempChildren_.swap(children_);
185 NotifyChangeWithCount(deletedIndex, -1, NotificationType::START_AND_END_CHANGE_POSITION);
186 MarkNeedSyncRenderTree(true);
187 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
188 }
189
OnDataBulkDeleted(size_t index,size_t count)190 void LazyForEachNode::OnDataBulkDeleted(size_t index, size_t count)
191 {
192 ACE_SCOPED_TRACE("LazyForEach OnDataBulkDeleted");
193 auto deletedIndex = static_cast<int32_t>(index);
194 if (builder_) {
195 builder_->SetUseNewInterface(false);
196 const auto& nodeList = builder_->OnDataBulkDeleted(index, count);
197 for (const auto& node : nodeList) {
198 if (node.second == nullptr) {
199 continue;
200 }
201 if (!node.second->OnRemoveFromParent(true)) {
202 AddDisappearingChild(node.second);
203 } else {
204 node.second->DetachFromMainTree();
205 }
206 builder_->ProcessOffscreenNode(node.second, true);
207 builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
208 }
209 builder_->clearDeletedNodes();
210 }
211 tempChildren_.clear();
212 tempChildren_.swap(children_);
213 NotifyChangeWithCount(deletedIndex, -static_cast<int32_t>(count), NotificationType::START_AND_END_CHANGE_POSITION);
214 MarkNeedSyncRenderTree(true);
215 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
216 }
217
OnDataChanged(size_t index)218 void LazyForEachNode::OnDataChanged(size_t index)
219 {
220 auto changedIndex = static_cast<int32_t>(index);
221 if (builder_) {
222 builder_->SetUseNewInterface(false);
223 builder_->OnDataChanged(index);
224 }
225 tempChildren_.clear();
226 tempChildren_.swap(children_);
227 NotifyChangeWithCount(changedIndex, 0, NotificationType::START_AND_END_CHANGE_POSITION);
228 MarkNeedSyncRenderTree(true);
229 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
230 }
231
OnDataBulkChanged(size_t index,size_t count)232 void LazyForEachNode::OnDataBulkChanged(size_t index, size_t count)
233 {
234 ACE_SCOPED_TRACE("LazyForEach OnDataBulkChanged");
235 auto changedIndex = static_cast<int32_t>(index);
236 if (builder_) {
237 builder_->SetUseNewInterface(false);
238 const auto& nodeList = builder_->OnDataBulkChanged(index, count);
239 for (const auto& node : nodeList) {
240 if (node.second == nullptr) {
241 continue;
242 }
243 if (!node.second->OnRemoveFromParent(true)) {
244 AddDisappearingChild(node.second);
245 } else {
246 node.second->DetachFromMainTree();
247 }
248 builder_->ProcessOffscreenNode(node.second, true);
249 builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
250 }
251 builder_->clearDeletedNodes();
252 }
253 tempChildren_.clear();
254 tempChildren_.swap(children_);
255 NotifyChangeWithCount(changedIndex, 0, NotificationType::START_CHANGE_POSITION);
256 NotifyChangeWithCount(changedIndex + static_cast<int32_t>(count) - 1, 0, NotificationType::END_CHANGE_POSITION);
257 MarkNeedSyncRenderTree(true);
258 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
259 }
260
OnDataMoveToNewPlace(size_t from,size_t to)261 void LazyForEachNode::OnDataMoveToNewPlace(size_t from, size_t to)
262 {
263 if (builder_) {
264 builder_->SetUseNewInterface(false);
265 builder_->OnDataMoveToNewPlace(from, to);
266 }
267 tempChildren_.clear();
268 tempChildren_.swap(children_);
269 NotifyChangeWithCount(static_cast<int32_t>(std::min(from, to)), 0, NotificationType::START_CHANGE_POSITION);
270 NotifyChangeWithCount(static_cast<int32_t>(std::max(from, to)), 0, NotificationType::END_CHANGE_POSITION);
271 MarkNeedSyncRenderTree(true);
272 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
273 }
274
OnDataMoved(size_t from,size_t to)275 void LazyForEachNode::OnDataMoved(size_t from, size_t to)
276 {
277 if (builder_) {
278 builder_->SetUseNewInterface(false);
279 builder_->OnDataMoved(from, to);
280 }
281 tempChildren_.clear();
282 tempChildren_.swap(children_);
283 NotifyChangeWithCount(static_cast<int32_t>(std::min(from, to)), 0, NotificationType::START_CHANGE_POSITION);
284 NotifyChangeWithCount(static_cast<int32_t>(std::max(from, to)), 0, NotificationType::END_CHANGE_POSITION);
285 MarkNeedSyncRenderTree(true);
286 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
287 }
288
OnDatasetChange(const std::list<V2::Operation> & DataOperations)289 void LazyForEachNode::OnDatasetChange(const std::list<V2::Operation>& DataOperations)
290 {
291 ACE_SCOPED_TRACE("LazyForEach OnDatasetChange");
292 int32_t initialChangedIndex = 0;
293 if (builder_) {
294 builder_->SetUseNewInterface(true);
295 std::pair<int32_t, std::list<std::pair<std::string, RefPtr<UINode>>>> pair =
296 builder_->OnDatasetChange(DataOperations);
297 initialChangedIndex = pair.first;
298 std::list<std::pair<std::string, RefPtr<UINode>>> nodeList = pair.second;
299 for (const auto& node : nodeList) {
300 if (node.second == nullptr) {
301 continue;
302 }
303 if (!node.second->OnRemoveFromParent(true)) {
304 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node.second);
305 } else {
306 node.second->DetachFromMainTree();
307 }
308 builder_->ProcessOffscreenNode(node.second, true);
309 builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
310 }
311 builder_->clearDeletedNodes();
312 }
313 tempChildren_.clear();
314 tempChildren_.swap(children_);
315 NotifyChangeWithCount(initialChangedIndex, 0, NotificationType::START_CHANGE_POSITION);
316 ParseOperations(DataOperations);
317 MarkNeedSyncRenderTree(true);
318 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
319 }
320
MarkNeedSyncRenderTree(bool needRebuild)321 void LazyForEachNode::MarkNeedSyncRenderTree(bool needRebuild)
322 {
323 if (needMarkParent_) {
324 UINode::MarkNeedSyncRenderTree(needRebuild);
325 }
326 }
327
GetFrameChildByIndex(uint32_t index,bool needBuild,bool isCache,bool addToRenderTree)328 RefPtr<UINode> LazyForEachNode::GetFrameChildByIndex(uint32_t index, bool needBuild, bool isCache, bool addToRenderTree)
329 {
330 if (index >= static_cast<uint32_t>(FrameCount())) {
331 return nullptr;
332 }
333 auto child = builder_->GetChildByIndex(index, needBuild, isCache);
334 if (!child.second) {
335 return nullptr;
336 }
337 if (isCache) {
338 child.second->SetParent(WeakClaim(this));
339 child.second->SetJSViewActive(false, true);
340 return child.second->GetFrameChildByIndex(0, needBuild);
341 }
342 if (isActive_) {
343 child.second->SetJSViewActive(true, true);
344 }
345 if (addToRenderTree) {
346 child.second->SetActive(true);
347 }
348 if (child.second->GetDepth() != GetDepth() + 1) {
349 child.second->SetDepth(GetDepth() + 1);
350 }
351 MarkNeedSyncRenderTree();
352 tempChildren_.clear();
353 tempChildren_.swap(children_);
354 child.second->SetParent(WeakClaim(this));
355 if (IsOnMainTree()) {
356 child.second->AttachToMainTree(false, GetContext());
357 }
358 PostIdleTask();
359 auto childNode = child.second->GetFrameChildByIndex(0, needBuild);
360 if (onMoveEvent_) {
361 InitDragManager(AceType::DynamicCast<FrameNode>(childNode));
362 }
363 return childNode;
364 }
365
GetIndexByUINode(const RefPtr<UINode> & uiNode) const366 int32_t LazyForEachNode::GetIndexByUINode(const RefPtr<UINode>& uiNode) const
367 {
368 if (!builder_) {
369 return -1;
370 }
371 auto items = builder_->GetAllChildren();
372 for (auto& [index, item] : items) {
373 if (item.second == uiNode) {
374 return index;
375 }
376 }
377 return -1;
378 }
379
RecycleItems(int32_t from,int32_t to)380 void LazyForEachNode::RecycleItems(int32_t from, int32_t to)
381 {
382 if (!builder_) {
383 return;
384 }
385 tempChildren_.clear();
386 tempChildren_.swap(children_);
387 for (auto index = from; index < to; index++) {
388 if (index >= startIndex_ && index < startIndex_ + count_) {
389 builder_->RecordOutOfBoundaryNodes(index - startIndex_);
390 }
391 }
392 PostIdleTask();
393 }
394
DoRemoveChildInRenderTree(uint32_t index,bool isAll)395 void LazyForEachNode::DoRemoveChildInRenderTree(uint32_t index, bool isAll)
396 {
397 if (!builder_) {
398 return;
399 }
400 tempChildren_.clear();
401 tempChildren_.swap(children_);
402 if (isAll) {
403 builder_->RemoveAllChild();
404 MarkNeedSyncRenderTree();
405 PostIdleTask();
406 }
407 }
408
DoSetActiveChildRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,bool showCache)409 void LazyForEachNode::DoSetActiveChildRange(
410 int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd, bool showCache)
411 {
412 if (!builder_) {
413 return;
414 }
415 if (showCache) {
416 start -= cacheStart;
417 end += cacheEnd;
418 builder_->SetShowCached(cacheStart, cacheEnd);
419 }
420 if (builder_->SetActiveChildRange(start, end)) {
421 tempChildren_.clear();
422 tempChildren_.swap(children_);
423 MarkNeedSyncRenderTree();
424 PostIdleTask();
425 }
426 }
427
GetChildren(bool notDetach) const428 const std::list<RefPtr<UINode>>& LazyForEachNode::GetChildren(bool notDetach) const
429 {
430 if (children_.empty()) {
431 LoadChildren(notDetach);
432
433 // if measure not done, return previous children
434 if (notDetach && children_.empty()) {
435 return tempChildren_;
436 }
437
438 tempChildren_.clear();
439 }
440 return children_;
441 }
442
UpdateChildrenFreezeState(bool isFreeze)443 void LazyForEachNode::UpdateChildrenFreezeState(bool isFreeze)
444 {
445 if (!builder_) {
446 return;
447 }
448 std::vector<UINode*> children;
449 builder_->GetAllItems(children);
450 for (const auto& child : children) {
451 if (child) {
452 child->SetFreeze(isFreeze);
453 }
454 }
455 }
456
LoadChildren(bool notDetach) const457 void LazyForEachNode::LoadChildren(bool notDetach) const
458 {
459 std::list<std::pair<std::string, RefPtr<UINode>>> childList;
460 const auto& items = builder_->GetItems(childList);
461
462 if (!notDetach) {
463 for (auto& node : childList) {
464 if (!node.second->OnRemoveFromParent(true)) {
465 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node.second);
466 } else {
467 node.second->DetachFromMainTree();
468 }
469 }
470 }
471
472 for (const auto& [index, item] : items) {
473 if (item.second) {
474 const_cast<LazyForEachNode*>(this)->RemoveDisappearingChild(item.second);
475 children_.push_back(item.second);
476 }
477 }
478 }
479
OnConfigurationUpdate(const ConfigurationChange & configurationChange)480 void LazyForEachNode::OnConfigurationUpdate(const ConfigurationChange& configurationChange)
481 {
482 if (configurationChange.IsNeedUpdate() && builder_) {
483 auto map = builder_->GetCachedUINodeMap();
484 for (auto& it : map) {
485 auto node = DynamicCast<UINode>(it.second.second);
486 if (node) {
487 node->UpdateConfigurationUpdate(configurationChange);
488 }
489 }
490 }
491 }
492
SetOnMove(std::function<void (int32_t,int32_t)> && onMove)493 void LazyForEachNode::SetOnMove(std::function<void(int32_t, int32_t)>&& onMove)
494 {
495 if (onMove && !onMoveEvent_) {
496 InitAllChilrenDragManager(true);
497 } else if (!onMove && onMoveEvent_) {
498 InitAllChilrenDragManager(false);
499 }
500 onMoveEvent_ = onMove;
501 }
502
MoveData(int32_t from,int32_t to)503 void LazyForEachNode::MoveData(int32_t from, int32_t to)
504 {
505 if (builder_) {
506 builder_->OnDataMoveToNewPlace(from, to);
507 builder_->UpdateMoveFromTo(from, to);
508 }
509 tempChildren_.clear();
510 tempChildren_.swap(children_);
511 MarkNeedSyncRenderTree(true);
512 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
513 }
514
FireOnMove(int32_t from,int32_t to)515 void LazyForEachNode::FireOnMove(int32_t from, int32_t to)
516 {
517 if (builder_) {
518 builder_->ResetMoveFromTo();
519 }
520 ForEachBaseNode::FireOnMove(from, to);
521 }
522
GetFrameNode(int32_t index)523 RefPtr<FrameNode> LazyForEachNode::GetFrameNode(int32_t index)
524 {
525 CHECK_NULL_RETURN(builder_, nullptr);
526 auto child = builder_->GetChildByIndex(index, false, false);
527 CHECK_NULL_RETURN(child.second, nullptr);
528 return AceType::DynamicCast<FrameNode>(child.second->GetFrameChildByIndex(0, true));
529 }
530
GetFrameNodeIndex(const RefPtr<FrameNode> & node,bool isExpanded)531 int32_t LazyForEachNode::GetFrameNodeIndex(const RefPtr<FrameNode>& node, bool isExpanded)
532 {
533 if (!isExpanded) {
534 return UINode::GetFrameNodeIndex(node, false);
535 }
536 CHECK_NULL_RETURN(builder_, -1);
537 return builder_->GetChildIndex(node);
538 }
539
InitDragManager(const RefPtr<FrameNode> & childNode)540 void LazyForEachNode::InitDragManager(const RefPtr<FrameNode>& childNode)
541 {
542 CHECK_NULL_VOID(childNode);
543 auto parentNode = GetParentFrameNode();
544 CHECK_NULL_VOID(parentNode);
545 if (parentNode->GetTag() != V2::LIST_ETS_TAG) {
546 return;
547 }
548 auto pattern = childNode->GetPattern<ListItemPattern>();
549 CHECK_NULL_VOID(pattern);
550 pattern->InitDragManager(AceType::Claim(this));
551 }
552
InitAllChilrenDragManager(bool init)553 void LazyForEachNode::InitAllChilrenDragManager(bool init)
554 {
555 auto parentNode = GetParentFrameNode();
556 CHECK_NULL_VOID(parentNode);
557 if (parentNode->GetTag() != V2::LIST_ETS_TAG) {
558 return;
559 }
560 const auto& children = GetChildren();
561 for (const auto& child : children) {
562 if (!child) {
563 continue;
564 }
565 auto childNode = child->GetFrameChildByIndex(0, false);
566 auto listItem = AceType::DynamicCast<FrameNode>(childNode);
567 if (!listItem) {
568 continue;
569 }
570
571 auto pattern = listItem->GetPattern<ListItemPattern>();
572 if (!pattern) {
573 continue;
574 }
575 if (init) {
576 pattern->InitDragManager(AceType::Claim(this));
577 } else {
578 pattern->DeInitDragManager();
579 }
580 }
581 }
582
NotifyChangeWithCount(int32_t index,int32_t count,NotificationType notificationType) const583 void LazyForEachNode::NotifyChangeWithCount(int32_t index, int32_t count, NotificationType notificationType) const
584 {
585 auto parent = GetParent();
586 int64_t accessibilityId = GetAccessibilityId();
587 if (parent) {
588 parent->NotifyChange(index, count, accessibilityId, notificationType);
589 }
590 }
591
ParseOperations(const std::list<V2::Operation> & dataOperations)592 void LazyForEachNode::ParseOperations(const std::list<V2::Operation>& dataOperations)
593 {
594 std::map<std::string, int32_t> operationTypeMap = { { "add", 1 }, { "delete", 2 }, { "change", 3 }, { "move", 4 },
595 { "exchange", 5 }, { "reload", 6 } };
596 constexpr int ADDOP = 1;
597 constexpr int DELETEOP = 2;
598 constexpr int CHANGEOP = 3;
599 constexpr int MOVEOP = 4;
600 constexpr int EXCHANGEOP = 5;
601 constexpr int RELOADOP = 6;
602 for (const auto& operation : dataOperations) {
603 switch (operationTypeMap[operation.type]) {
604 case ADDOP:
605 NotifyChangeWithCount(operation.index, operation.count, NotificationType::END_CHANGE_POSITION);
606 break;
607 case DELETEOP:
608 NotifyChangeWithCount(operation.index, -operation.count, NotificationType::END_CHANGE_POSITION);
609 break;
610 case CHANGEOP:
611 NotifyChangeWithCount(operation.index + operation.count - 1, 0, NotificationType::END_CHANGE_POSITION);
612 break;
613 case MOVEOP:
614 NotifyChangeWithCount(std::max(operation.coupleIndex.first, operation.coupleIndex.second), 0,
615 NotificationType::END_CHANGE_POSITION);
616 break;
617 case EXCHANGEOP:
618 NotifyChangeWithCount(operation.coupleIndex.second, 0, NotificationType::END_CHANGE_POSITION);
619 break;
620 case RELOADOP:
621 if (builder_) {
622 int32_t endChangePos = std::max(builder_->GetHistoryTotalCount(), FrameCount());
623 NotifyChangeWithCount(endChangePos, 0, NotificationType::END_CHANGE_POSITION);
624 }
625 break;
626 }
627 }
628 }
629 } // namespace OHOS::Ace::NG
630