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