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