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