1 /*
2  * Copyright (c) 2021 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/list/list_component.h"
17 
18 #include "frameworks/core/components/ifelse/if_else_component.h"
19 
20 namespace OHOS::Ace {
21 
ListComponent(const std::list<RefPtr<Component>> & children)22 ListComponent::ListComponent(const std::list<RefPtr<Component>>& children) : ComponentGroup(children)
23 {
24     needPreBuild_ = true;
25 }
26 
CreateElement()27 RefPtr<Element> ListComponent::CreateElement()
28 {
29     // This func will be called repeatedly when list in dialog.
30     needUpdateElement_ = true;
31     auto listElement = AceType::MakeRefPtr<ListElement>();
32     listElement_ = AceType::WeakClaim(AceType::RawPtr(listElement));
33     return listElement;
34 }
35 
CreateRenderNode()36 RefPtr<RenderNode> ListComponent::CreateRenderNode()
37 {
38     return RenderList::Create();
39 }
40 
InitStyle(const RefPtr<ListTheme> & theme)41 void ListComponent::InitStyle(const RefPtr<ListTheme>& theme)
42 {
43     if (theme) {
44         gradientWidth_ = theme->GetGradientWidth();
45         backgroundColor_ = theme->GetBackgroundColor();
46     }
47 }
48 
SetFlexAlign(FlexAlign flexAlign)49 void ListComponent::SetFlexAlign(FlexAlign flexAlign)
50 {
51     if (flexAlign < FlexAlign::FLEX_START || flexAlign > FlexAlign::STRETCH) {
52         LOGW("Invalid flexAlign %{public}d", flexAlign);
53         return;
54     }
55     flexAlign_ = flexAlign;
56 }
57 
SetColumnCount(int32_t count)58 void ListComponent::SetColumnCount(int32_t count)
59 {
60     if (count <= 0) {
61         LOGW("Invalid ColumnCount %{public}d", count);
62         return;
63     }
64     columnCount_ = count;
65 }
66 
SetColumnExtent(int32_t extent)67 void ListComponent::SetColumnExtent(int32_t extent)
68 {
69     if (extent <= 0) {
70         return;
71     }
72     columnExtent_ = extent;
73 }
74 
SetItemExtent(const Dimension & itemExtent)75 void ListComponent::SetItemExtent(const Dimension& itemExtent)
76 {
77     if (!itemExtent.IsValid()) {
78         return;
79     }
80     itemExtent_ = itemExtent;
81 }
82 
SetWidth(double width)83 void ListComponent::SetWidth(double width)
84 {
85     if (width <= 0.0) {
86         LOGW("Invalid Width %{public}lf", width);
87         return;
88     }
89     width_ = width;
90 }
91 
SetHeight(double height)92 void ListComponent::SetHeight(double height)
93 {
94     if (height <= 0.0) {
95         LOGW("Invalid Height %{public}lf", height);
96         return;
97     }
98     height_ = height;
99 }
100 
InsertChild(int32_t position,const RefPtr<Component> & child)101 void ListComponent::InsertChild(int32_t position, const RefPtr<Component>& child)
102 {
103     if (position < 0) {
104         LOGE("InsertChild: the position is negative");
105         return;
106     }
107     auto pos = static_cast<uint32_t>(position);
108     auto item = ListItemComponent::GetListItem(child);
109     if (!item) {
110         LOGE("InsertChild: no list item in child");
111         return;
112     }
113 
114     const auto& children = GetChildren();
115     if (!child || pos > children.size()) {
116         return;
117     }
118 
119     if (pos == children.size()) {
120         AppendChild(child);
121         return;
122     }
123 
124     int32_t current = 0;
125     auto it = children.begin();
126     while (it != children.end()) {
127         auto listItemComponent = ListItemComponent::GetListItem(*it);
128         if (listItemComponent && listItemComponent->GetOperation() == LIST_ITEM_OP_REMOVE) {
129             --current;
130         }
131 
132         if (current == static_cast<int32_t>(pos)) {
133             break;
134         }
135 
136         ++current;
137         ++it;
138     }
139 
140     item->SetOperation(LIST_ITEM_OP_ADD);
141     needUpdateElement_ = true;
142     ComponentGroup::InsertChild(std::distance(children.begin(), it), child);
143 }
144 
AppendChild(const RefPtr<Component> & child)145 void ListComponent::AppendChild(const RefPtr<Component>& child)
146 {
147     auto item = ListItemComponent::GetListItem(child);
148     if (!item) {
149         auto multiComposed = AceType::DynamicCast<MultiComposedComponent>(child);
150         if (!multiComposed) {
151             return;
152         }
153 
154         for (const auto& childComponent : multiComposed->GetChildren()) {
155             AppendChild(childComponent);
156         }
157         return;
158     }
159     if (needDivider_) {
160         item->MarkNeedDivider(needDivider_);
161         item->SetDividerColor(dividerColor_);
162         item->SetDividerHeight(dividerHeight_);
163         item->SetDividerLength(dividerLength_);
164         item->SetDividerOrigin(dividerOrigin_);
165     }
166 
167     item->SetIndex(GetChildren().size());
168     item->SetOperation(LIST_ITEM_OP_ADD);
169 
170     needUpdateElement_ = true;
171     // Version 1.0 will wrap ComposedComponent for ListItem by DomNode.
172     if (AceType::InstanceOf<ComposedComponent>(child)) {
173         ComponentGroup::AppendChild(child);
174     } else {
175         ComponentGroup::AppendChild(
176             AceType::MakeRefPtr<ComposedComponent>((const char*)&item, "ListItemWrapper", child));
177     }
178 }
179 
RemoveChild(const RefPtr<Component> & child)180 void ListComponent::RemoveChild(const RefPtr<Component>& child)
181 {
182     auto item = ListItemComponent::GetListItem(child);
183     if (!item) {
184         LOGE("RemoveChild: no list item in child");
185         return;
186     }
187 
188     if (beginIndex_ != LIST_PARAM_INVAID && endIndex_ != LIST_PARAM_INVAID) {
189         ComponentGroup::RemoveChild(child);
190         needUpdateElement_ = true;
191     } else {
192         if (item->GetOperation() == LIST_ITEM_OP_ADD) {
193             ComponentGroup::RemoveChild(child);
194             return;
195         }
196         item->SetOperation(LIST_ITEM_OP_REMOVE);
197         needUpdateElement_ = true;
198     }
199 }
200 
SetGroupState(int32_t expandIndex,bool expand)201 void ListComponent::SetGroupState(int32_t expandIndex, bool expand)
202 {
203     auto listElement = listElement_.Upgrade();
204     if (!listElement) {
205         LOGE("SetGroupState failed");
206         return;
207     }
208     listElement->SetGroupState(expandIndex, expand);
209 }
210 
211 } // namespace OHOS::Ace
212