1446ac6d7SIngo Weinhold /*
2446ac6d7SIngo Weinhold * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3446ac6d7SIngo Weinhold * Distributed under the terms of the MIT License.
4446ac6d7SIngo Weinhold */
5446ac6d7SIngo Weinhold
6446ac6d7SIngo Weinhold
7446ac6d7SIngo Weinhold #include "ListSelectionModel.h"
8446ac6d7SIngo Weinhold
9446ac6d7SIngo Weinhold
10446ac6d7SIngo Weinhold // #pragma mark - ListSelectionModel
11446ac6d7SIngo Weinhold
12446ac6d7SIngo Weinhold
ListSelectionModel()13446ac6d7SIngo Weinhold ListSelectionModel::ListSelectionModel()
14446ac6d7SIngo Weinhold {
15446ac6d7SIngo Weinhold }
16446ac6d7SIngo Weinhold
17446ac6d7SIngo Weinhold
ListSelectionModel(const ListSelectionModel & other)18*63481b10SIngo Weinhold ListSelectionModel::ListSelectionModel(const ListSelectionModel& other)
19*63481b10SIngo Weinhold {
20*63481b10SIngo Weinhold *this = other;
21*63481b10SIngo Weinhold }
22*63481b10SIngo Weinhold
23*63481b10SIngo Weinhold
~ListSelectionModel()24446ac6d7SIngo Weinhold ListSelectionModel::~ListSelectionModel()
25446ac6d7SIngo Weinhold {
26446ac6d7SIngo Weinhold }
27446ac6d7SIngo Weinhold
28446ac6d7SIngo Weinhold
29446ac6d7SIngo Weinhold void
Clear()30446ac6d7SIngo Weinhold ListSelectionModel::Clear()
31446ac6d7SIngo Weinhold {
32446ac6d7SIngo Weinhold int32 selectedCount = fSelectedItems.Count();
33446ac6d7SIngo Weinhold if (selectedCount > 0) {
34446ac6d7SIngo Weinhold int32 firstSelected = fSelectedItems[0];
35446ac6d7SIngo Weinhold int32 lastSelected = fSelectedItems[selectedCount - 1];
36446ac6d7SIngo Weinhold
37446ac6d7SIngo Weinhold fSelectedItems.Clear();
38446ac6d7SIngo Weinhold
39446ac6d7SIngo Weinhold _NotifyItemsDeselected(firstSelected, lastSelected - firstSelected + 1);
40446ac6d7SIngo Weinhold }
41446ac6d7SIngo Weinhold }
42446ac6d7SIngo Weinhold
43446ac6d7SIngo Weinhold
44446ac6d7SIngo Weinhold bool
SelectItems(int32 itemIndex,int32 count,bool extendSelection)45446ac6d7SIngo Weinhold ListSelectionModel::SelectItems(int32 itemIndex, int32 count,
46446ac6d7SIngo Weinhold bool extendSelection)
47446ac6d7SIngo Weinhold {
48446ac6d7SIngo Weinhold int32 endItemIndex = itemIndex + count;
49446ac6d7SIngo Weinhold
50446ac6d7SIngo Weinhold int32 index;
51446ac6d7SIngo Weinhold if (extendSelection) {
52446ac6d7SIngo Weinhold if (count <= 0)
53446ac6d7SIngo Weinhold return true;
54446ac6d7SIngo Weinhold
55446ac6d7SIngo Weinhold index = _FindItem(itemIndex);
56446ac6d7SIngo Weinhold
57446ac6d7SIngo Weinhold // count already selected items
58446ac6d7SIngo Weinhold int32 alreadySelectedCount = _CountSelectedItemsInRange(index,
59446ac6d7SIngo Weinhold endItemIndex);
60446ac6d7SIngo Weinhold if (alreadySelectedCount == count)
61446ac6d7SIngo Weinhold return true;
62446ac6d7SIngo Weinhold
63446ac6d7SIngo Weinhold // make room for the new items
64446ac6d7SIngo Weinhold if (!fSelectedItems.InsertUninitialized(index + alreadySelectedCount,
65446ac6d7SIngo Weinhold count - alreadySelectedCount)) {
66446ac6d7SIngo Weinhold return false;
67446ac6d7SIngo Weinhold }
68446ac6d7SIngo Weinhold } else {
69446ac6d7SIngo Weinhold // TODO: Don't clear -- just resize to the right size!
70446ac6d7SIngo Weinhold Clear();
71446ac6d7SIngo Weinhold if (count <= 0)
72446ac6d7SIngo Weinhold return true;
73446ac6d7SIngo Weinhold
74446ac6d7SIngo Weinhold index = 0;
75446ac6d7SIngo Weinhold if (!fSelectedItems.AddUninitialized(count))
76446ac6d7SIngo Weinhold return false;
77446ac6d7SIngo Weinhold }
78446ac6d7SIngo Weinhold
79446ac6d7SIngo Weinhold for (int32 i = 0; i < count; i++)
80446ac6d7SIngo Weinhold fSelectedItems[index + i] = itemIndex + i;
81446ac6d7SIngo Weinhold
82446ac6d7SIngo Weinhold _NotifyItemsSelected(itemIndex, count);
83446ac6d7SIngo Weinhold
84446ac6d7SIngo Weinhold return true;
85446ac6d7SIngo Weinhold }
86446ac6d7SIngo Weinhold
87446ac6d7SIngo Weinhold
88446ac6d7SIngo Weinhold void
DeselectItems(int32 itemIndex,int32 count)89446ac6d7SIngo Weinhold ListSelectionModel::DeselectItems(int32 itemIndex, int32 count)
90446ac6d7SIngo Weinhold {
91446ac6d7SIngo Weinhold int32 endItemIndex = itemIndex + count;
92446ac6d7SIngo Weinhold int32 index = _FindItem(itemIndex);
93446ac6d7SIngo Weinhold
94446ac6d7SIngo Weinhold // count actually selected items
95446ac6d7SIngo Weinhold int32 actuallySelectedCount = _CountSelectedItemsInRange(index,
96446ac6d7SIngo Weinhold endItemIndex);
97446ac6d7SIngo Weinhold if (actuallySelectedCount == 0)
98446ac6d7SIngo Weinhold return;
99446ac6d7SIngo Weinhold
100446ac6d7SIngo Weinhold fSelectedItems.Remove(index, actuallySelectedCount);
101446ac6d7SIngo Weinhold
102446ac6d7SIngo Weinhold _NotifyItemsDeselected(itemIndex, count);
103446ac6d7SIngo Weinhold }
104446ac6d7SIngo Weinhold
105446ac6d7SIngo Weinhold
106446ac6d7SIngo Weinhold void
ItemsAdded(int32 itemIndex,int32 count)107446ac6d7SIngo Weinhold ListSelectionModel::ItemsAdded(int32 itemIndex, int32 count)
108446ac6d7SIngo Weinhold {
109446ac6d7SIngo Weinhold if (count <= 0)
110446ac6d7SIngo Weinhold return;
111446ac6d7SIngo Weinhold
112446ac6d7SIngo Weinhold // re-index following items
113446ac6d7SIngo Weinhold int32 index = _FindItem(itemIndex);
114446ac6d7SIngo Weinhold int32 selectedCount = fSelectedItems.Count();
115446ac6d7SIngo Weinhold for (int32 i = index; i < selectedCount; i++)
116446ac6d7SIngo Weinhold fSelectedItems[i] += count;
117446ac6d7SIngo Weinhold }
118446ac6d7SIngo Weinhold
119446ac6d7SIngo Weinhold
120446ac6d7SIngo Weinhold void
ItemsRemoved(int32 itemIndex,int32 count)121446ac6d7SIngo Weinhold ListSelectionModel::ItemsRemoved(int32 itemIndex, int32 count)
122446ac6d7SIngo Weinhold {
123446ac6d7SIngo Weinhold if (count <= 0)
124446ac6d7SIngo Weinhold return;
125446ac6d7SIngo Weinhold
126446ac6d7SIngo Weinhold int32 index = _FindItem(itemIndex);
127446ac6d7SIngo Weinhold
128446ac6d7SIngo Weinhold // count selected items in the range
129446ac6d7SIngo Weinhold int32 actuallySelectedCount = _CountSelectedItemsInRange(index,
130446ac6d7SIngo Weinhold itemIndex + count);
131446ac6d7SIngo Weinhold if (actuallySelectedCount > 0)
132446ac6d7SIngo Weinhold fSelectedItems.Remove(index, actuallySelectedCount);
133446ac6d7SIngo Weinhold
134446ac6d7SIngo Weinhold // re-index following items
135446ac6d7SIngo Weinhold int32 selectedCount = fSelectedItems.Count();
136446ac6d7SIngo Weinhold for (int32 i = index; i < selectedCount; i++)
137446ac6d7SIngo Weinhold fSelectedItems[i] -= count;
138446ac6d7SIngo Weinhold }
139446ac6d7SIngo Weinhold
140446ac6d7SIngo Weinhold
141446ac6d7SIngo Weinhold bool
AddListener(Listener * listener)142446ac6d7SIngo Weinhold ListSelectionModel::AddListener(Listener* listener)
143446ac6d7SIngo Weinhold {
144446ac6d7SIngo Weinhold return fListeners.AddItem(listener);
145446ac6d7SIngo Weinhold }
146446ac6d7SIngo Weinhold
147446ac6d7SIngo Weinhold
148446ac6d7SIngo Weinhold void
RemoveListener(Listener * listener)149446ac6d7SIngo Weinhold ListSelectionModel::RemoveListener(Listener* listener)
150446ac6d7SIngo Weinhold {
151446ac6d7SIngo Weinhold fListeners.RemoveItem(listener);
152446ac6d7SIngo Weinhold }
153446ac6d7SIngo Weinhold
154446ac6d7SIngo Weinhold
155*63481b10SIngo Weinhold ListSelectionModel&
operator =(const ListSelectionModel & other)156*63481b10SIngo Weinhold ListSelectionModel::operator=(const ListSelectionModel& other)
157*63481b10SIngo Weinhold {
158*63481b10SIngo Weinhold Clear();
159*63481b10SIngo Weinhold
160*63481b10SIngo Weinhold fSelectedItems = other.fSelectedItems;
161*63481b10SIngo Weinhold
162*63481b10SIngo Weinhold int32 selectedCount = CountSelectedItems();
163*63481b10SIngo Weinhold if (selectedCount > 0) {
164*63481b10SIngo Weinhold int32 firstSelected = fSelectedItems[0];
165*63481b10SIngo Weinhold int32 lastSelected = fSelectedItems[selectedCount - 1];
166*63481b10SIngo Weinhold _NotifyItemsDeselected(firstSelected, lastSelected - firstSelected + 1);
167*63481b10SIngo Weinhold }
168*63481b10SIngo Weinhold
169*63481b10SIngo Weinhold return *this;
170*63481b10SIngo Weinhold }
171*63481b10SIngo Weinhold
172*63481b10SIngo Weinhold
173446ac6d7SIngo Weinhold int32
_FindItem(int32 itemIndex) const174446ac6d7SIngo Weinhold ListSelectionModel::_FindItem(int32 itemIndex) const
175446ac6d7SIngo Weinhold {
176446ac6d7SIngo Weinhold // binary search the index of the first item >= itemIndex
177446ac6d7SIngo Weinhold int32 lower = 0;
178446ac6d7SIngo Weinhold int32 upper = fSelectedItems.Count();
179446ac6d7SIngo Weinhold
180446ac6d7SIngo Weinhold while (lower < upper) {
181446ac6d7SIngo Weinhold int32 mid = (lower + upper) / 2;
182446ac6d7SIngo Weinhold
183446ac6d7SIngo Weinhold if (fSelectedItems[mid] < itemIndex)
184446ac6d7SIngo Weinhold lower = mid + 1;
185446ac6d7SIngo Weinhold else
186446ac6d7SIngo Weinhold upper = mid;
187446ac6d7SIngo Weinhold }
188446ac6d7SIngo Weinhold
189446ac6d7SIngo Weinhold return lower;
190446ac6d7SIngo Weinhold }
191446ac6d7SIngo Weinhold
192446ac6d7SIngo Weinhold
193446ac6d7SIngo Weinhold int32
_CountSelectedItemsInRange(int32 index,int32 endItemIndex) const194446ac6d7SIngo Weinhold ListSelectionModel::_CountSelectedItemsInRange(int32 index,
195446ac6d7SIngo Weinhold int32 endItemIndex) const
196446ac6d7SIngo Weinhold {
197446ac6d7SIngo Weinhold int32 count = 0;
198446ac6d7SIngo Weinhold int32 selectedCount = fSelectedItems.Count();
199446ac6d7SIngo Weinhold for (int32 i = index; i < selectedCount; i++) {
200446ac6d7SIngo Weinhold if (SelectedItemAt(i) >= endItemIndex)
201446ac6d7SIngo Weinhold break;
202446ac6d7SIngo Weinhold count++;
203446ac6d7SIngo Weinhold }
204446ac6d7SIngo Weinhold
205446ac6d7SIngo Weinhold return count;
206446ac6d7SIngo Weinhold }
207446ac6d7SIngo Weinhold
208446ac6d7SIngo Weinhold
209446ac6d7SIngo Weinhold void
_NotifyItemsSelected(int32 index,int32 count)210446ac6d7SIngo Weinhold ListSelectionModel::_NotifyItemsSelected(int32 index, int32 count)
211446ac6d7SIngo Weinhold {
212446ac6d7SIngo Weinhold int32 listenerCount = fListeners.CountItems();
213446ac6d7SIngo Weinhold for (int32 i = listenerCount - 1; i >= 0; i--)
214446ac6d7SIngo Weinhold fListeners.ItemAt(i)->ItemsSelected(this, index, count);
215446ac6d7SIngo Weinhold }
216446ac6d7SIngo Weinhold
217446ac6d7SIngo Weinhold
218446ac6d7SIngo Weinhold void
_NotifyItemsDeselected(int32 index,int32 count)219446ac6d7SIngo Weinhold ListSelectionModel::_NotifyItemsDeselected(int32 index, int32 count)
220446ac6d7SIngo Weinhold {
221446ac6d7SIngo Weinhold int32 listenerCount = fListeners.CountItems();
222446ac6d7SIngo Weinhold for (int32 i = listenerCount - 1; i >= 0; i--)
223446ac6d7SIngo Weinhold fListeners.ItemAt(i)->ItemsDeselected(this, index, count);
224446ac6d7SIngo Weinhold }
225446ac6d7SIngo Weinhold
226446ac6d7SIngo Weinhold
227446ac6d7SIngo Weinhold // #pragma mark - Listener
228446ac6d7SIngo Weinhold
229446ac6d7SIngo Weinhold
~Listener()230446ac6d7SIngo Weinhold ListSelectionModel::Listener::~Listener()
231446ac6d7SIngo Weinhold {
232446ac6d7SIngo Weinhold }
233446ac6d7SIngo Weinhold
234446ac6d7SIngo Weinhold
235446ac6d7SIngo Weinhold void
ItemsSelected(ListSelectionModel * model,int32 index,int32 count)236446ac6d7SIngo Weinhold ListSelectionModel::Listener::ItemsSelected(ListSelectionModel* model,
237446ac6d7SIngo Weinhold int32 index, int32 count)
238446ac6d7SIngo Weinhold {
239446ac6d7SIngo Weinhold }
240446ac6d7SIngo Weinhold
241446ac6d7SIngo Weinhold
242446ac6d7SIngo Weinhold void
ItemsDeselected(ListSelectionModel * model,int32 index,int32 count)243446ac6d7SIngo Weinhold ListSelectionModel::Listener::ItemsDeselected(ListSelectionModel* model,
244446ac6d7SIngo Weinhold int32 index, int32 count)
245446ac6d7SIngo Weinhold {
246446ac6d7SIngo Weinhold }
247