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