Author: bonefish Date: 2009-12-08 22:46:49 +0100 (Tue, 08 Dec 2009) New Revision: 34567 Changeset: http://dev.haiku-os.org/changeset/34567/haiku Added: haiku/trunk/src/apps/debuganalyzer/gui/ListSelectionModel.cpp haiku/trunk/src/apps/debuganalyzer/gui/ListSelectionModel.h Modified: haiku/trunk/src/apps/debuganalyzer/gui/Jamfile Log: Added class ListSelectionModel, representing a selection of list (i.e. indexed) elements. Modified: haiku/trunk/src/apps/debuganalyzer/gui/Jamfile =================================================================== --- haiku/trunk/src/apps/debuganalyzer/gui/Jamfile 2009-12-08 21:44:01 UTC (rev 34566) +++ haiku/trunk/src/apps/debuganalyzer/gui/Jamfile 2009-12-08 21:46:49 UTC (rev 34567) @@ -13,6 +13,7 @@ AbstractGeneralPage.cpp ColorCheckBox.cpp HeaderView.cpp + ListSelectionModel.cpp SubWindow.cpp SubWindowManager.cpp : Added: haiku/trunk/src/apps/debuganalyzer/gui/ListSelectionModel.cpp =================================================================== --- haiku/trunk/src/apps/debuganalyzer/gui/ListSelectionModel.cpp (rev 0) +++ haiku/trunk/src/apps/debuganalyzer/gui/ListSelectionModel.cpp 2009-12-08 21:46:49 UTC (rev 34567) @@ -0,0 +1,224 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Distributed under the terms of the MIT License. + */ + + +#include "ListSelectionModel.h" + + +// #pragma mark - ListSelectionModel + + +ListSelectionModel::ListSelectionModel() + : + fItemCount(0) +{ +} + + +ListSelectionModel::~ListSelectionModel() +{ +} + + +void +ListSelectionModel::Clear() +{ + int32 selectedCount = fSelectedItems.Count(); + if (selectedCount > 0) { + int32 firstSelected = fSelectedItems[0]; + int32 lastSelected = fSelectedItems[selectedCount - 1]; + + fSelectedItems.Clear(); + + _NotifyItemsDeselected(firstSelected, lastSelected - firstSelected + 1); + } +} + + +bool +ListSelectionModel::SelectItems(int32 itemIndex, int32 count, + bool extendSelection) +{ + int32 endItemIndex = itemIndex + count; + + int32 index; + if (extendSelection) { + if (count <= 0) + return true; + + index = _FindItem(itemIndex); + + // count already selected items + int32 alreadySelectedCount = _CountSelectedItemsInRange(index, + endItemIndex); + if (alreadySelectedCount == count) + return true; + + // make room for the new items + if (!fSelectedItems.InsertUninitialized(index + alreadySelectedCount, + count - alreadySelectedCount)) { + return false; + } + } else { + // TODO: Don't clear -- just resize to the right size! + Clear(); + if (count <= 0) + return true; + + index = 0; + if (!fSelectedItems.AddUninitialized(count)) + return false; + } + + for (int32 i = 0; i < count; i++) + fSelectedItems[index + i] = itemIndex + i; + + _NotifyItemsSelected(itemIndex, count); + + return true; +} + + +void +ListSelectionModel::DeselectItems(int32 itemIndex, int32 count) +{ + int32 endItemIndex = itemIndex + count; + int32 index = _FindItem(itemIndex); + + // count actually selected items + int32 actuallySelectedCount = _CountSelectedItemsInRange(index, + endItemIndex); + if (actuallySelectedCount == 0) + return; + + fSelectedItems.Remove(index, actuallySelectedCount); + + _NotifyItemsDeselected(itemIndex, count); +} + + +void +ListSelectionModel::ItemsAdded(int32 itemIndex, int32 count) +{ + if (count <= 0) + return; + + // re-index following items + int32 index = _FindItem(itemIndex); + int32 selectedCount = fSelectedItems.Count(); + for (int32 i = index; i < selectedCount; i++) + fSelectedItems[i] += count; +} + + +void +ListSelectionModel::ItemsRemoved(int32 itemIndex, int32 count) +{ + if (count <= 0) + return; + + int32 index = _FindItem(itemIndex); + + // count selected items in the range + int32 actuallySelectedCount = _CountSelectedItemsInRange(index, + itemIndex + count); + if (actuallySelectedCount > 0) + fSelectedItems.Remove(index, actuallySelectedCount); + + // re-index following items + int32 selectedCount = fSelectedItems.Count(); + for (int32 i = index; i < selectedCount; i++) + fSelectedItems[i] -= count; +} + + +bool +ListSelectionModel::AddListener(Listener* listener) +{ + return fListeners.AddItem(listener); +} + + +void +ListSelectionModel::RemoveListener(Listener* listener) +{ + fListeners.RemoveItem(listener); +} + + +int32 +ListSelectionModel::_FindItem(int32 itemIndex) const +{ + // binary search the index of the first item >= itemIndex + int32 lower = 0; + int32 upper = fSelectedItems.Count(); + + while (lower < upper) { + int32 mid = (lower + upper) / 2; + + if (fSelectedItems[mid] < itemIndex) + lower = mid + 1; + else + upper = mid; + } + + return lower; +} + + +int32 +ListSelectionModel::_CountSelectedItemsInRange(int32 index, + int32 endItemIndex) const +{ + int32 count = 0; + int32 selectedCount = fSelectedItems.Count(); + for (int32 i = index; i < selectedCount; i++) { + if (SelectedItemAt(i) >= endItemIndex) + break; + count++; + } + + return count; +} + + +void +ListSelectionModel::_NotifyItemsSelected(int32 index, int32 count) +{ + int32 listenerCount = fListeners.CountItems(); + for (int32 i = listenerCount - 1; i >= 0; i--) + fListeners.ItemAt(i)->ItemsSelected(this, index, count); +} + + +void +ListSelectionModel::_NotifyItemsDeselected(int32 index, int32 count) +{ + int32 listenerCount = fListeners.CountItems(); + for (int32 i = listenerCount - 1; i >= 0; i--) + fListeners.ItemAt(i)->ItemsDeselected(this, index, count); +} + + +// #pragma mark - Listener + + +ListSelectionModel::Listener::~Listener() +{ +} + + +void +ListSelectionModel::Listener::ItemsSelected(ListSelectionModel* model, + int32 index, int32 count) +{ +} + + +void +ListSelectionModel::Listener::ItemsDeselected(ListSelectionModel* model, + int32 index, int32 count) +{ +} Added: haiku/trunk/src/apps/debuganalyzer/gui/ListSelectionModel.h =================================================================== --- haiku/trunk/src/apps/debuganalyzer/gui/ListSelectionModel.h (rev 0) +++ haiku/trunk/src/apps/debuganalyzer/gui/ListSelectionModel.h 2009-12-08 21:46:49 UTC (rev 34567) @@ -0,0 +1,103 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Distributed under the terms of the MIT License. + */ +#ifndef LIST_SELECTION_MODEL_H +#define LIST_SELECTION_MODEL_H + + +#include <SupportDefs.h> + +#include <ObjectList.h> + +#include "../debugger/util/Array.h" + + +class ListSelectionModel { +public: + class Listener; + +public: + ListSelectionModel(); + ~ListSelectionModel(); + + int32 CountSelectedItems() const + { return fSelectedItems.Count(); } + int32 SelectedItemAt(int32 index) const; + bool IsItemSelected(int32 itemIndex) const; + + void Clear(); + bool SelectItem(int32 itemIndex, + bool extendSelection); + bool SelectItems(int32 itemIndex, int32 count, + bool extendSelection); + void DeselectItem(int32 itemIndex); + void DeselectItems(int32 itemIndex, int32 count); + + void ItemsAdded(int32 itemIndex, int32 count); + void ItemsRemoved(int32 itemIndex, int32 count); + + bool AddListener(Listener* listener); + void RemoveListener(Listener* listener); + +private: + typedef BObjectList<Listener> ListenerList; + +private: + int32 _FindItem(int32 itemIndex) const; + int32 _CountSelectedItemsInRange(int32 index, + int32 endItemIndex) const; + + void _NotifyItemsSelected(int32 index, int32 count); + void _NotifyItemsDeselected(int32 index, + int32 count); + +private: + int32 fItemCount; + Array<int32> fSelectedItems; + ListenerList fListeners; +}; + + +class ListSelectionModel::Listener { +public: + virtual ~Listener(); + + virtual void ItemsSelected(ListSelectionModel* model, + int32 index, int32 count); + virtual void ItemsDeselected(ListSelectionModel* model, + int32 index, int32 count); +}; + + +inline bool +ListSelectionModel::IsItemSelected(int32 itemIndex) const +{ + int32 index = _FindItem(itemIndex); + return index < fSelectedItems.Count() && fSelectedItems[index] == itemIndex; +} + + +inline int32 +ListSelectionModel::SelectedItemAt(int32 index) const +{ + return index >= 0 && index < fSelectedItems.Count() + ? fSelectedItems[index] : -1; +} + + +inline bool +ListSelectionModel::SelectItem(int32 itemIndex, bool extendSelection) +{ + return SelectItems(itemIndex, 1, extendSelection); +} + + +inline void +ListSelectionModel::DeselectItem(int32 itemIndex) +{ + DeselectItems(itemIndex, 1); +} + + +#endif // LIST_SELECTION_MODEL_H