1/* 2 * Copyright 2006-2007, 2023, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephan A��mus <superstippi@gmx.de> 7 * Zardshard 8 */ 9#ifndef CONTAINER_H 10#define CONTAINER_H 11 12 13#include <stdio.h> 14#include <string.h> 15 16#include <List.h> 17#include <OS.h> 18#include <Referenceable.h> 19 20#include "IconBuild.h" 21 22class BReferenceable; 23 24 25_BEGIN_ICON_NAMESPACE 26 27 28template<class Type> 29class ContainerListener { 30 public: 31 ContainerListener(); 32 virtual ~ContainerListener(); 33 34 virtual void ItemAdded(Type* item, int32 index) = 0; 35 virtual void ItemRemoved(Type* item) = 0; 36}; 37 38 39/*! 40 Wraps \c BList and provides some additional features. 41 42 -# It allows listeners to listen when an item is added or removed. 43 -# It can take ownership of the objects that it stores. 44 -# It casts list items into the correct type. 45*/ 46// TODO: some of these features are provided by BObjectList 47template<class Type> 48class Container { 49 public: 50 Container(bool ownsItems); 51 virtual ~Container(); 52 53 bool AddItem(Type* item); 54 bool AddItem(Type* item, int32 index); 55 bool RemoveItem(Type* item); 56 Type* RemoveItem(int32 index); 57 58 void MakeEmpty(); 59 60 int32 CountItems() const; 61 bool HasItem(Type* item) const; 62 int32 IndexOf(Type* item) const; 63 64 Type* ItemAt(int32 index) const; 65 Type* ItemAtFast(int32 index) const; 66 67 bool AddListener(ContainerListener<Type>* listener); 68 bool RemoveListener(ContainerListener<Type>* listener); 69 70 private: 71 void _NotifyItemAdded(Type* item, int32 index) const; 72 void _NotifyItemRemoved(Type* item) const; 73 74 private: 75 BList fItems; 76 bool fOwnsItems; 77 78 BList fListeners; 79}; 80 81 82template<class Type> 83ContainerListener<Type>::ContainerListener() {} 84 85 86template<class Type> 87ContainerListener<Type>::~ContainerListener() {} 88 89 90template<class Type> 91Container<Type>::Container(bool ownsItems) 92 : fItems(16), 93 fOwnsItems(ownsItems), 94 fListeners(2) 95{ 96} 97 98 99template<class Type> 100Container<Type>::~Container() 101{ 102 int32 count = fListeners.CountItems(); 103 if (count > 0) { 104 debugger("~Container() - there are still" 105 "listeners attached\n"); 106 } 107 MakeEmpty(); 108} 109 110 111// #pragma mark - 112 113 114template<class Type> 115bool 116Container<Type>::AddItem(Type* item) 117{ 118 return AddItem(item, CountItems()); 119} 120 121 122template<class Type> 123bool 124Container<Type>::AddItem(Type* item, int32 index) 125{ 126 if (!item) 127 return false; 128 129 // prevent adding the same item twice 130 if (HasItem(item)) 131 return false; 132 133 if (fItems.AddItem((void*)item, index)) { 134 _NotifyItemAdded(item, index); 135 return true; 136 } 137 138 fprintf(stderr, "Container::AddItem() - out of memory!\n"); 139 return false; 140} 141 142 143template<class Type> 144bool 145Container<Type>::RemoveItem(Type* item) 146{ 147 if (fItems.RemoveItem((void*)item)) { 148 _NotifyItemRemoved(item); 149 return true; 150 } 151 152 return false; 153} 154 155 156template<class Type> 157Type* 158Container<Type>::RemoveItem(int32 index) 159{ 160 Type* item = (Type*)fItems.RemoveItem(index); 161 if (item) { 162 _NotifyItemRemoved(item); 163 } 164 165 return item; 166} 167 168 169template<class Type> 170void 171Container<Type>::MakeEmpty() 172{ 173 int32 count = CountItems(); 174 for (int32 i = 0; i < count; i++) { 175 Type* item = ItemAtFast(i); 176 _NotifyItemRemoved(item); 177#ifdef ICON_O_MATIC 178 if (fOwnsItems) 179 item->ReleaseReference(); 180#else 181 if (fOwnsItems) 182 delete item; 183#endif 184 } 185 fItems.MakeEmpty(); 186} 187 188 189// #pragma mark - 190 191 192template<class Type> 193int32 194Container<Type>::CountItems() const 195{ 196 return fItems.CountItems(); 197} 198 199 200template<class Type> 201bool 202Container<Type>::HasItem(Type* item) const 203{ 204 return fItems.HasItem(item); 205} 206 207 208template<class Type> 209int32 210Container<Type>::IndexOf(Type* item) const 211{ 212 return fItems.IndexOf((void*)item); 213} 214 215 216template<class Type> 217Type* 218Container<Type>::ItemAt(int32 index) const 219{ 220 return (Type*)fItems.ItemAt(index); 221} 222 223 224template<class Type> 225Type* 226Container<Type>::ItemAtFast(int32 index) const 227{ 228 return (Type*)fItems.ItemAtFast(index); 229} 230 231 232// #pragma mark - 233 234 235template<class Type> 236bool 237Container<Type>::AddListener(ContainerListener<Type>* listener) 238{ 239 if (listener && !fListeners.HasItem(listener)) 240 return fListeners.AddItem(listener); 241 return false; 242} 243 244 245template<class Type> 246bool 247Container<Type>::RemoveListener(ContainerListener<Type>* listener) 248{ 249 return fListeners.RemoveItem(listener); 250} 251 252 253// #pragma mark - 254 255 256template<class Type> 257void 258Container<Type>::_NotifyItemAdded(Type* item, int32 index) const 259{ 260 BList listeners(fListeners); 261 int32 count = listeners.CountItems(); 262 for (int32 i = 0; i < count; i++) { 263 ContainerListener<Type>* listener 264 = (ContainerListener<Type>*)listeners.ItemAtFast(i); 265 listener->ItemAdded(item, index); 266 } 267} 268 269 270template<class Type> 271void 272Container<Type>::_NotifyItemRemoved(Type* item) const 273{ 274 BList listeners(fListeners); 275 int32 count = listeners.CountItems(); 276 for (int32 i = 0; i < count; i++) { 277 ContainerListener<Type>* listener 278 = (ContainerListener<Type>*)listeners.ItemAtFast(i); 279 listener->ItemRemoved(item); 280 } 281} 282 283 284_END_ICON_NAMESPACE 285 286 287#endif // CONTAINER_H 288