[NUI] Introduce CollectionView and related classes. (#2525)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / RecyclerView / SelectionList.cs
1 /* Copyright (c) 2021 Samsung Electronics Co., Ltd.
2  *
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
17 using System;
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.Collections.Specialized;
21
22 namespace Tizen.NUI.Components
23 {
24     // Used by the CollectionView to keep track of (and respond to changes in) the SelectedItems property
25     internal class SelectionList : IList<object>
26     {
27         static readonly IList<object> selectEmpty = new List<object>(0);
28         readonly CollectionView ColView;
29         readonly IList<object> internalList;
30         IList<object> shadowList;
31         bool externalChange;
32
33         public SelectionList(CollectionView colView, IList<object> items = null)
34         {
35             ColView = colView ?? throw new ArgumentNullException(nameof(colView));
36             internalList = items ?? new List<object>();
37             shadowList = Copy();
38
39             if (items is INotifyCollectionChanged incc)
40             {
41                 incc.CollectionChanged += OnCollectionChanged;
42             }
43         }
44
45         public object this[int index] { get => internalList[index]; set => internalList[index] = value; }
46
47         public int Count => internalList.Count;
48
49         public bool IsReadOnly => false;
50
51         public void Add(object item)
52         {
53             externalChange = true;
54             internalList.Add(item);
55             externalChange = false;
56
57             ColView.SelectedItemsPropertyChanged(shadowList, internalList);
58             shadowList.Add(item);
59         }
60
61         public void Clear()
62         {
63             externalChange = true;
64             internalList.Clear();
65             externalChange = false;
66
67             ColView.SelectedItemsPropertyChanged(shadowList, selectEmpty);
68             shadowList.Clear();
69         }
70
71         public bool Contains(object item)
72         {
73             return internalList.Contains(item);
74         }
75
76         public void CopyTo(object[] array, int arrayIndex)
77         {
78             internalList.CopyTo(array, arrayIndex);
79         }
80
81         public IEnumerator<object> GetEnumerator()
82         {
83             return internalList.GetEnumerator();
84         }
85
86         public int IndexOf(object item)
87         {
88             return internalList.IndexOf(item);
89         }
90
91         public void Insert(int index, object item)
92         {
93             externalChange = true;
94             internalList.Insert(index, item);
95             externalChange = false;
96
97             ColView.SelectedItemsPropertyChanged(shadowList, internalList);
98             shadowList.Insert(index, item);
99         }
100
101         public bool Remove(object item)
102         {
103             externalChange = true;
104             var removed = internalList.Remove(item);
105             externalChange = false;
106
107             if (removed)
108             {
109                 ColView.SelectedItemsPropertyChanged(shadowList, internalList);
110                 shadowList.Remove(item);
111             }
112
113             return removed;
114         }
115
116         public void RemoveAt(int index)
117         {
118             externalChange = true;
119             internalList.RemoveAt(index);
120             externalChange = false;
121
122             ColView.SelectedItemsPropertyChanged(shadowList, internalList);
123             shadowList.RemoveAt(index);
124         }
125
126         IEnumerator IEnumerable.GetEnumerator()
127         {
128             return internalList.GetEnumerator();
129         }
130
131         List<object> Copy()
132         {
133             var items = new List<object>();
134             for (int n = 0; n < internalList.Count; n++)
135             {
136                 items.Add(internalList[n]);
137             }
138
139             return items;
140         }
141
142         void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
143         {
144             if (externalChange)
145             {
146                 // If this change was initiated by a renderer or direct manipulation of ColllectionView.SelectedItems,
147                 // we don't need to send a selection change notification
148                 return;
149             }
150
151             // This change is coming from a bound viewmodel property
152             // Emit a selection change notification, then bring the shadow copy up-to-date
153             ColView.SelectedItemsPropertyChanged(shadowList, internalList);
154             shadowList = Copy();
155         }
156     }
157 }