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 13ListSelectionModel::ListSelectionModel() 14{ 15} 16 17 18ListSelectionModel::ListSelectionModel(const ListSelectionModel& other) 19{ 20 *this = other; 21} 22 23 24ListSelectionModel::~ListSelectionModel() 25{ 26} 27 28 29void 30ListSelectionModel::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 44bool 45ListSelectionModel::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 88void 89ListSelectionModel::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 106void 107ListSelectionModel::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 120void 121ListSelectionModel::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 141bool 142ListSelectionModel::AddListener(Listener* listener) 143{ 144 return fListeners.AddItem(listener); 145} 146 147 148void 149ListSelectionModel::RemoveListener(Listener* listener) 150{ 151 fListeners.RemoveItem(listener); 152} 153 154 155ListSelectionModel& 156ListSelectionModel::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 173int32 174ListSelectionModel::_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 193int32 194ListSelectionModel::_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 209void 210ListSelectionModel::_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 218void 219ListSelectionModel::_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 230ListSelectionModel::Listener::~Listener() 231{ 232} 233 234 235void 236ListSelectionModel::Listener::ItemsSelected(ListSelectionModel* model, 237 int32 index, int32 count) 238{ 239} 240 241 242void 243ListSelectionModel::Listener::ItemsDeselected(ListSelectionModel* model, 244 int32 index, int32 count) 245{ 246} 247