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