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