1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include "ListSelectionModel.h"
8
9
10 // #pragma mark - ListSelectionModel
11
12
ListSelectionModel()13 ListSelectionModel::ListSelectionModel()
14 {
15 }
16
17
ListSelectionModel(const ListSelectionModel & other)18 ListSelectionModel::ListSelectionModel(const ListSelectionModel& other)
19 {
20 *this = other;
21 }
22
23
~ListSelectionModel()24 ListSelectionModel::~ListSelectionModel()
25 {
26 }
27
28
29 void
Clear()30 ListSelectionModel::Clear()
31 {
32 int32 selectedCount = fSelectedItems.Count();
33 if (selectedCount > 0) {
34 int32 firstSelected = fSelectedItems[0];
35 int32 lastSelected = fSelectedItems[selectedCount - 1];
36
37 fSelectedItems.Clear();
38
39 _NotifyItemsDeselected(firstSelected, lastSelected - firstSelected + 1);
40 }
41 }
42
43
44 bool
SelectItems(int32 itemIndex,int32 count,bool extendSelection)45 ListSelectionModel::SelectItems(int32 itemIndex, int32 count,
46 bool extendSelection)
47 {
48 int32 endItemIndex = itemIndex + count;
49
50 int32 index;
51 if (extendSelection) {
52 if (count <= 0)
53 return true;
54
55 index = _FindItem(itemIndex);
56
57 // count already selected items
58 int32 alreadySelectedCount = _CountSelectedItemsInRange(index,
59 endItemIndex);
60 if (alreadySelectedCount == count)
61 return true;
62
63 // make room for the new items
64 if (!fSelectedItems.InsertUninitialized(index + alreadySelectedCount,
65 count - alreadySelectedCount)) {
66 return false;
67 }
68 } else {
69 // TODO: Don't clear -- just resize to the right size!
70 Clear();
71 if (count <= 0)
72 return true;
73
74 index = 0;
75 if (!fSelectedItems.AddUninitialized(count))
76 return false;
77 }
78
79 for (int32 i = 0; i < count; i++)
80 fSelectedItems[index + i] = itemIndex + i;
81
82 _NotifyItemsSelected(itemIndex, count);
83
84 return true;
85 }
86
87
88 void
DeselectItems(int32 itemIndex,int32 count)89 ListSelectionModel::DeselectItems(int32 itemIndex, int32 count)
90 {
91 int32 endItemIndex = itemIndex + count;
92 int32 index = _FindItem(itemIndex);
93
94 // count actually selected items
95 int32 actuallySelectedCount = _CountSelectedItemsInRange(index,
96 endItemIndex);
97 if (actuallySelectedCount == 0)
98 return;
99
100 fSelectedItems.Remove(index, actuallySelectedCount);
101
102 _NotifyItemsDeselected(itemIndex, count);
103 }
104
105
106 void
ItemsAdded(int32 itemIndex,int32 count)107 ListSelectionModel::ItemsAdded(int32 itemIndex, int32 count)
108 {
109 if (count <= 0)
110 return;
111
112 // re-index following items
113 int32 index = _FindItem(itemIndex);
114 int32 selectedCount = fSelectedItems.Count();
115 for (int32 i = index; i < selectedCount; i++)
116 fSelectedItems[i] += count;
117 }
118
119
120 void
ItemsRemoved(int32 itemIndex,int32 count)121 ListSelectionModel::ItemsRemoved(int32 itemIndex, int32 count)
122 {
123 if (count <= 0)
124 return;
125
126 int32 index = _FindItem(itemIndex);
127
128 // count selected items in the range
129 int32 actuallySelectedCount = _CountSelectedItemsInRange(index,
130 itemIndex + count);
131 if (actuallySelectedCount > 0)
132 fSelectedItems.Remove(index, actuallySelectedCount);
133
134 // re-index following items
135 int32 selectedCount = fSelectedItems.Count();
136 for (int32 i = index; i < selectedCount; i++)
137 fSelectedItems[i] -= count;
138 }
139
140
141 bool
AddListener(Listener * listener)142 ListSelectionModel::AddListener(Listener* listener)
143 {
144 return fListeners.AddItem(listener);
145 }
146
147
148 void
RemoveListener(Listener * listener)149 ListSelectionModel::RemoveListener(Listener* listener)
150 {
151 fListeners.RemoveItem(listener);
152 }
153
154
155 ListSelectionModel&
operator =(const ListSelectionModel & other)156 ListSelectionModel::operator=(const ListSelectionModel& other)
157 {
158 Clear();
159
160 fSelectedItems = other.fSelectedItems;
161
162 int32 selectedCount = CountSelectedItems();
163 if (selectedCount > 0) {
164 int32 firstSelected = fSelectedItems[0];
165 int32 lastSelected = fSelectedItems[selectedCount - 1];
166 _NotifyItemsDeselected(firstSelected, lastSelected - firstSelected + 1);
167 }
168
169 return *this;
170 }
171
172
173 int32
_FindItem(int32 itemIndex) const174 ListSelectionModel::_FindItem(int32 itemIndex) const
175 {
176 // binary search the index of the first item >= itemIndex
177 int32 lower = 0;
178 int32 upper = fSelectedItems.Count();
179
180 while (lower < upper) {
181 int32 mid = (lower + upper) / 2;
182
183 if (fSelectedItems[mid] < itemIndex)
184 lower = mid + 1;
185 else
186 upper = mid;
187 }
188
189 return lower;
190 }
191
192
193 int32
_CountSelectedItemsInRange(int32 index,int32 endItemIndex) const194 ListSelectionModel::_CountSelectedItemsInRange(int32 index,
195 int32 endItemIndex) const
196 {
197 int32 count = 0;
198 int32 selectedCount = fSelectedItems.Count();
199 for (int32 i = index; i < selectedCount; i++) {
200 if (SelectedItemAt(i) >= endItemIndex)
201 break;
202 count++;
203 }
204
205 return count;
206 }
207
208
209 void
_NotifyItemsSelected(int32 index,int32 count)210 ListSelectionModel::_NotifyItemsSelected(int32 index, int32 count)
211 {
212 int32 listenerCount = fListeners.CountItems();
213 for (int32 i = listenerCount - 1; i >= 0; i--)
214 fListeners.ItemAt(i)->ItemsSelected(this, index, count);
215 }
216
217
218 void
_NotifyItemsDeselected(int32 index,int32 count)219 ListSelectionModel::_NotifyItemsDeselected(int32 index, int32 count)
220 {
221 int32 listenerCount = fListeners.CountItems();
222 for (int32 i = listenerCount - 1; i >= 0; i--)
223 fListeners.ItemAt(i)->ItemsDeselected(this, index, count);
224 }
225
226
227 // #pragma mark - Listener
228
229
~Listener()230 ListSelectionModel::Listener::~Listener()
231 {
232 }
233
234
235 void
ItemsSelected(ListSelectionModel * model,int32 index,int32 count)236 ListSelectionModel::Listener::ItemsSelected(ListSelectionModel* model,
237 int32 index, int32 count)
238 {
239 }
240
241
242 void
ItemsDeselected(ListSelectionModel * model,int32 index,int32 count)243 ListSelectionModel::Listener::ItemsDeselected(ListSelectionModel* model,
244 int32 index, int32 count)
245 {
246 }
247