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     NotifyChangeWithCount(static_cast<int32_t>(FrameCount()), 0, NotificationType::END_CHANGE_POSITION);
129     MarkNeedSyncRenderTree(true);
130     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
131 }
132 
OnDataAdded(size_t index)133 void LazyForEachNode::OnDataAdded(size_t index)
134 {
135     ACE_SCOPED_TRACE("LazyForEach OnDataAdded");
136     auto insertIndex = static_cast<int32_t>(index);
137     if (builder_) {
138         builder_->SetUseNewInterface(false);
139         builder_->OnDataAdded(index);
140     }
141     tempChildren_.clear();
142     tempChildren_.swap(children_);
143     NotifyChangeWithCount(insertIndex, 1, NotificationType::START_AND_END_CHANGE_POSITION);
144     MarkNeedSyncRenderTree(true);
145     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
146 }
147 
OnDataBulkAdded(size_t index,size_t count)148 void LazyForEachNode::OnDataBulkAdded(size_t index, size_t count)
149 {
150     ACE_SCOPED_TRACE("LazyForEach OnDataBulkAdded");
151     auto insertIndex = static_cast<int32_t>(index);
152     if (builder_) {
153         builder_->SetUseNewInterface(false);
154         builder_->OnDataBulkAdded(index, count);
155     }
156     tempChildren_.clear();
157     tempChildren_.swap(children_);
158     NotifyChangeWithCount(insertIndex, static_cast<int32_t>(count), NotificationType::START_AND_END_CHANGE_POSITION);
159     MarkNeedSyncRenderTree(true);
160     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
161 }
162 
OnDataDeleted(size_t index)163 void LazyForEachNode::OnDataDeleted(size_t index)
164 {
165     ACE_SCOPED_TRACE("LazyForEach OnDataDeleted");
166     auto deletedIndex = static_cast<int32_t>(index);
167     if (builder_) {
168         builder_->SetUseNewInterface(false);
169         auto node = builder_->OnDataDeleted(index);
170 
171         if (node) {
172             if (!node->OnRemoveFromParent(true)) {
173                 AddDisappearingChild(node);
174             } else {
175                 node->DetachFromMainTree();
176             }
177             builder_->ProcessOffscreenNode(node, true);
178         }
179     }
180     tempChildren_.clear();
181     tempChildren_.swap(children_);
182     NotifyChangeWithCount(deletedIndex, -1, NotificationType::START_AND_END_CHANGE_POSITION);
183     MarkNeedSyncRenderTree(true);
184     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
185 }
186 
OnDataBulkDeleted(size_t index,size_t count)187 void LazyForEachNode::OnDataBulkDeleted(size_t index, size_t count)
188 {
189     ACE_SCOPED_TRACE("LazyForEach OnDataBulkDeleted");
190     auto deletedIndex = static_cast<int32_t>(index);
191     if (builder_) {
192         builder_->SetUseNewInterface(false);
193         const auto& nodeList = builder_->OnDataBulkDeleted(index, count);
194         for (const auto& node : nodeList) {
195             if (node.second == nullptr) {
196                 continue;
197             }
198             if (!node.second->OnRemoveFromParent(true)) {
199                 AddDisappearingChild(node.second);
200             } else {
201                 node.second->DetachFromMainTree();
202             }
203             builder_->ProcessOffscreenNode(node.second, true);
204             builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
205         }
206         builder_->clearDeletedNodes();
207     }
208     tempChildren_.clear();
209     tempChildren_.swap(children_);
210     NotifyChangeWithCount(deletedIndex, -static_cast<int32_t>(count), NotificationType::START_AND_END_CHANGE_POSITION);
211     MarkNeedSyncRenderTree(true);
212     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
213 }
214 
OnDataChanged(size_t index)215 void LazyForEachNode::OnDataChanged(size_t index)
216 {
217     auto changedIndex = static_cast<int32_t>(index);
218     if (builder_) {
219         builder_->SetUseNewInterface(false);
220         builder_->OnDataChanged(index);
221     }
222     tempChildren_.clear();
223     tempChildren_.swap(children_);
224     NotifyChangeWithCount(changedIndex, 0, NotificationType::START_AND_END_CHANGE_POSITION);
225     MarkNeedSyncRenderTree(true);
226     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
227 }
228 
OnDataBulkChanged(size_t index,size_t count)229 void LazyForEachNode::OnDataBulkChanged(size_t index, size_t count)
230 {
231     ACE_SCOPED_TRACE("LazyForEach OnDataBulkChanged");
232     auto changedIndex = static_cast<int32_t>(index);
233     if (builder_) {
234         builder_->SetUseNewInterface(false);
235         const auto& nodeList = builder_->OnDataBulkChanged(index, count);
236         for (const auto& node : nodeList) {
237             if (node.second == nullptr) {
238                 continue;
239             }
240             if (!node.second->OnRemoveFromParent(true)) {
241                 AddDisappearingChild(node.second);
242             } else {
243                 node.second->DetachFromMainTree();
244             }
245             builder_->ProcessOffscreenNode(node.second, true);
246             builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
247         }
248         builder_->clearDeletedNodes();
249     }
250     tempChildren_.clear();
251     tempChildren_.swap(children_);
252     NotifyChangeWithCount(changedIndex, 0, NotificationType::START_CHANGE_POSITION);
253     NotifyChangeWithCount(changedIndex + static_cast<int32_t>(count) - 1, 0, NotificationType::END_CHANGE_POSITION);
254     MarkNeedSyncRenderTree(true);
255     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
256 }
257 
OnDataMoveToNewPlace(size_t from,size_t to)258 void LazyForEachNode::OnDataMoveToNewPlace(size_t from, size_t to)
259 {
260     if (builder_) {
261         builder_->SetUseNewInterface(false);
262         builder_->OnDataMoveToNewPlace(from, to);
263     }
264     tempChildren_.clear();
265     tempChildren_.swap(children_);
266     NotifyChangeWithCount(static_cast<int32_t>(std::min(from, to)), 0, NotificationType::START_CHANGE_POSITION);
267     NotifyChangeWithCount(static_cast<int32_t>(std::max(from, to)), 0, NotificationType::END_CHANGE_POSITION);
268     MarkNeedSyncRenderTree(true);
269     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
270 }
271 
OnDataMoved(size_t from,size_t to)272 void LazyForEachNode::OnDataMoved(size_t from, size_t to)
273 {
274     if (builder_) {
275         builder_->SetUseNewInterface(false);
276         builder_->OnDataMoved(from, to);
277     }
278     tempChildren_.clear();
279     tempChildren_.swap(children_);
280     NotifyChangeWithCount(static_cast<int32_t>(std::min(from, to)), 0, NotificationType::START_CHANGE_POSITION);
281     NotifyChangeWithCount(static_cast<int32_t>(std::max(from, to)), 0, NotificationType::END_CHANGE_POSITION);
282     MarkNeedSyncRenderTree(true);
283     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
284 }
285 
OnDatasetChange(const std::list<V2::Operation> & DataOperations)286 void LazyForEachNode::OnDatasetChange(const std::list<V2::Operation>& DataOperations)
287 {
288     ACE_SCOPED_TRACE("LazyForEach OnDatasetChange");
289     int32_t initialChangedIndex = 0;
290     if (builder_) {
291         builder_->SetUseNewInterface(true);
292         std::pair<int32_t, std::list<std::pair<std::string, RefPtr<UINode>>>> pair =
293             builder_->OnDatasetChange(DataOperations);
294         initialChangedIndex = pair.first;
295         std::list<std::pair<std::string, RefPtr<UINode>>> nodeList = pair.second;
296         for (const auto& node : nodeList) {
297             if (node.second == nullptr) {
298                 continue;
299             }
300             if (!node.second->OnRemoveFromParent(true)) {
301                 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node.second);
302             } else {
303                 node.second->DetachFromMainTree();
304             }
305             builder_->ProcessOffscreenNode(node.second, true);
306             builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
307         }
308         builder_->clearDeletedNodes();
309     }
310     tempChildren_.clear();
311     tempChildren_.swap(children_);
312     NotifyChangeWithCount(initialChangedIndex, 0, NotificationType::START_CHANGE_POSITION);
313     ParseOperations(DataOperations);
314     MarkNeedSyncRenderTree(true);
315     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
316 }
317 
MarkNeedSyncRenderTree(bool needRebuild)318 void LazyForEachNode::MarkNeedSyncRenderTree(bool needRebuild)
319 {
320     if (needMarkParent_) {
321         UINode::MarkNeedSyncRenderTree(needRebuild);
322     }
323 }
324 
GetFrameChildByIndex(uint32_t index,bool needBuild,bool isCache,bool addToRenderTree)325 RefPtr<UINode> LazyForEachNode::GetFrameChildByIndex(uint32_t index, bool needBuild, bool isCache, bool addToRenderTree)
326 {
327     if (index >= static_cast<uint32_t>(FrameCount())) {
328         return nullptr;
329     }
330     auto child = builder_->GetChildByIndex(index, needBuild, isCache);
331     if (!child.second) {
332         return nullptr;
333     }
334     if (isCache) {
335         child.second->SetParent(WeakClaim(this));
336         child.second->SetJSViewActive(false, true);
337         return child.second->GetFrameChildByIndex(0, needBuild);
338     }
339     if (isActive_) {
340         child.second->SetJSViewActive(true, true);
341     }
342     if (addToRenderTree) {
343         child.second->SetActive(true);
344     }
345     if (child.second->GetDepth() != GetDepth() + 1) {
346         child.second->SetDepth(GetDepth() + 1);
347     }
348     MarkNeedSyncRenderTree();
349     tempChildren_.clear();
350     tempChildren_.swap(children_);
351     child.second->SetParent(WeakClaim(this));
352     if (IsOnMainTree()) {
353         child.second->AttachToMainTree(false, GetContext());
354     }
355     PostIdleTask();
356     auto childNode = child.second->GetFrameChildByIndex(0, needBuild);
357     if (onMoveEvent_) {
358         InitDragManager(AceType::DynamicCast<FrameNode>(childNode));
359     }
360     return childNode;
361 }
362 
GetIndexByUINode(const RefPtr<UINode> & uiNode) const363 int32_t LazyForEachNode::GetIndexByUINode(const RefPtr<UINode>& uiNode) const
364 {
365     if (!builder_) {
366         return -1;
367     }
368     auto items = builder_->GetAllChildren();
369     for (auto& [index, item] : items) {
370         if (item.second == uiNode) {
371             return index;
372         }
373     }
374     return -1;
375 }
376 
RecycleItems(int32_t from,int32_t to)377 void LazyForEachNode::RecycleItems(int32_t from, int32_t to)
378 {
379     if (!builder_) {
380         return;
381     }
382     tempChildren_.clear();
383     tempChildren_.swap(children_);
384     for (auto index = from; index < to; index++) {
385         if (index >= startIndex_ && index < startIndex_ + count_) {
386             builder_->RecordOutOfBoundaryNodes(index - startIndex_);
387         }
388     }
389     PostIdleTask();
390 }
391 
DoRemoveChildInRenderTree(uint32_t index,bool isAll)392 void LazyForEachNode::DoRemoveChildInRenderTree(uint32_t index, bool isAll)
393 {
394     if (!builder_) {
395         return;
396     }
397     tempChildren_.clear();
398     tempChildren_.swap(children_);
399     if (isAll) {
400         builder_->RemoveAllChild();
401         MarkNeedSyncRenderTree();
402         PostIdleTask();
403     }
404 }
405 
DoSetActiveChildRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,bool showCache)406 void LazyForEachNode::DoSetActiveChildRange(
407     int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd, bool showCache)
408 {
409     if (!builder_) {
410         return;
411     }
412     if (showCache) {
413         start -= cacheStart;
414         end += cacheEnd;
415         builder_->SetShowCached(cacheStart, cacheEnd);
416     }
417     if (builder_->SetActiveChildRange(start, end)) {
418         tempChildren_.clear();
419         tempChildren_.swap(children_);
420         MarkNeedSyncRenderTree();
421         PostIdleTask();
422     }
423 }
424 
GetChildren(bool notDetach) const425 const std::list<RefPtr<UINode>>& LazyForEachNode::GetChildren(bool notDetach) const
426 {
427     if (children_.empty()) {
428         LoadChildren(notDetach);
429 
430         // if measure not done, return previous children
431         if (notDetach && children_.empty()) {
432             return tempChildren_;
433         }
434 
435         tempChildren_.clear();
436     }
437     return children_;
438 }
439 
UpdateChildrenFreezeState(bool isFreeze)440 void LazyForEachNode::UpdateChildrenFreezeState(bool isFreeze)
441 {
442     if (!builder_) {
443         return;
444     }
445     std::vector<UINode*> children;
446     builder_->GetAllItems(children);
447     for (const auto& child : children) {
448         if (child) {
449             child->SetFreeze(isFreeze);
450         }
451     }
452 }
453 
LoadChildren(bool notDetach) const454 void LazyForEachNode::LoadChildren(bool notDetach) const
455 {
456     std::list<std::pair<std::string, RefPtr<UINode>>> childList;
457     const auto& items = builder_->GetItems(childList);
458 
459     if (!notDetach) {
460         for (auto& node : childList) {
461             if (!node.second->OnRemoveFromParent(true)) {
462                 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node.second);
463             } else {
464                 node.second->DetachFromMainTree();
465             }
466         }
467     }
468 
469     for (const auto& [index, item] : items) {
470         if (item.second) {
471             const_cast<LazyForEachNode*>(this)->RemoveDisappearingChild(item.second);
472             children_.push_back(item.second);
473         }
474     }
475 }
476 
OnConfigurationUpdate(const ConfigurationChange & configurationChange)477 void LazyForEachNode::OnConfigurationUpdate(const ConfigurationChange& configurationChange)
478 {
479     if (configurationChange.IsNeedUpdate() && builder_) {
480         auto map = builder_->GetCachedUINodeMap();
481         for (auto& it : map) {
482             auto node = DynamicCast<UINode>(it.second.second);
483             if (node) {
484                 node->UpdateConfigurationUpdate(configurationChange);
485             }
486         }
487     }
488 }
489 
SetOnMove(std::function<void (int32_t,int32_t)> && onMove)490 void LazyForEachNode::SetOnMove(std::function<void(int32_t, int32_t)>&& onMove)
491 {
492     if (onMove && !onMoveEvent_) {
493         InitAllChilrenDragManager(true);
494     } else if (!onMove && onMoveEvent_) {
495         InitAllChilrenDragManager(false);
496     }
497     onMoveEvent_ = onMove;
498 }
499 
MoveData(int32_t from,int32_t to)500 void LazyForEachNode::MoveData(int32_t from, int32_t to)
501 {
502     if (builder_) {
503         builder_->OnDataMoveToNewPlace(from, to);
504         builder_->UpdateMoveFromTo(from, to);
505     }
506     tempChildren_.clear();
507     tempChildren_.swap(children_);
508     MarkNeedSyncRenderTree(true);
509     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
510 }
511 
FireOnMove(int32_t from,int32_t to)512 void LazyForEachNode::FireOnMove(int32_t from, int32_t to)
513 {
514     if (builder_) {
515         builder_->ResetMoveFromTo();
516     }
517     ForEachBaseNode::FireOnMove(from, to);
518 }
519 
GetFrameNode(int32_t index)520 RefPtr<FrameNode> LazyForEachNode::GetFrameNode(int32_t index)
521 {
522     CHECK_NULL_RETURN(builder_, nullptr);
523     auto child = builder_->GetChildByIndex(index, false, false);
524     CHECK_NULL_RETURN(child.second, nullptr);
525     return AceType::DynamicCast<FrameNode>(child.second->GetFrameChildByIndex(0, true));
526 }
527 
GetFrameNodeIndex(const RefPtr<FrameNode> & node,bool isExpanded)528 int32_t LazyForEachNode::GetFrameNodeIndex(const RefPtr<FrameNode>& node, bool isExpanded)
529 {
530     if (!isExpanded) {
531         return UINode::GetFrameNodeIndex(node, false);
532     }
533     CHECK_NULL_RETURN(builder_, -1);
534     return builder_->GetChildIndex(node);
535 }
536 
InitDragManager(const RefPtr<FrameNode> & childNode)537 void LazyForEachNode::InitDragManager(const RefPtr<FrameNode>& childNode)
538 {
539     CHECK_NULL_VOID(childNode);
540     auto parentNode = GetParentFrameNode();
541     CHECK_NULL_VOID(parentNode);
542     if (parentNode->GetTag() != V2::LIST_ETS_TAG) {
543         return;
544     }
545     auto pattern = childNode->GetPattern<ListItemPattern>();
546     CHECK_NULL_VOID(pattern);
547     pattern->InitDragManager(AceType::Claim(this));
548 }
549 
InitAllChilrenDragManager(bool init)550 void LazyForEachNode::InitAllChilrenDragManager(bool init)
551 {
552     auto parentNode = GetParentFrameNode();
553     CHECK_NULL_VOID(parentNode);
554     if (parentNode->GetTag() != V2::LIST_ETS_TAG) {
555         return;
556     }
557     const auto& children = GetChildren();
558     for (const auto& child : children) {
559         if (!child) {
560             continue;
561         }
562         auto childNode = child->GetFrameChildByIndex(0, false);
563         auto listItem = AceType::DynamicCast<FrameNode>(childNode);
564         if (!listItem) {
565             continue;
566         }
567 
568         auto pattern = listItem->GetPattern<ListItemPattern>();
569         if (!pattern) {
570             continue;
571         }
572         if (init) {
573             pattern->InitDragManager(AceType::Claim(this));
574         } else {
575             pattern->DeInitDragManager();
576         }
577     }
578 }
579 
NotifyChangeWithCount(int32_t index,int32_t count,NotificationType notificationType) const580 void LazyForEachNode::NotifyChangeWithCount(int32_t index, int32_t count, NotificationType notificationType) const
581 {
582     auto parent = GetParent();
583     int64_t accessibilityId = GetAccessibilityId();
584     if (parent) {
585         parent->NotifyChange(index, count, accessibilityId, notificationType);
586     }
587 }
588 
ParseOperations(const std::list<V2::Operation> & dataOperations)589 void LazyForEachNode::ParseOperations(const std::list<V2::Operation>& dataOperations)
590 {
591     std::map<std::string, int32_t> operationTypeMap = { { "add", 1 }, { "delete", 2 }, { "change", 3 }, { "move", 4 },
592         { "exchange", 5 }, { "reload", 6 } };
593     constexpr int ADDOP = 1;
594     constexpr int DELETEOP = 2;
595     constexpr int CHANGEOP = 3;
596     constexpr int MOVEOP = 4;
597     constexpr int EXCHANGEOP = 5;
598     constexpr int RELOADOP = 6;
599     for (const auto& operation : dataOperations) {
600         switch (operationTypeMap[operation.type]) {
601             case ADDOP:
602                 NotifyChangeWithCount(operation.index, operation.count, NotificationType::END_CHANGE_POSITION);
603                 break;
604             case DELETEOP:
605                 NotifyChangeWithCount(operation.index, -operation.count, NotificationType::END_CHANGE_POSITION);
606                 break;
607             case CHANGEOP:
608                 NotifyChangeWithCount(operation.index + operation.count - 1, 0, NotificationType::END_CHANGE_POSITION);
609                 break;
610             case MOVEOP:
611                 NotifyChangeWithCount(std::max(operation.coupleIndex.first, operation.coupleIndex.second), 0,
612                     NotificationType::END_CHANGE_POSITION);
613                 break;
614             case EXCHANGEOP:
615                 NotifyChangeWithCount(operation.coupleIndex.second, 0, NotificationType::END_CHANGE_POSITION);
616                 break;
617             case RELOADOP:
618                 NotifyChangeWithCount(static_cast<int32_t>(FrameCount()), 0, NotificationType::END_CHANGE_POSITION);
619                 break;
620         }
621     }
622 }
623 } // namespace OHOS::Ace::NG
624