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 22 class BReferenceable; 23 24 25 _BEGIN_ICON_NAMESPACE 26 27 28 template<class Type> 29 class 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 47 template<class Type> 48 class 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 82 template<class Type> 83 ContainerListener<Type>::ContainerListener() {} 84 85 86 template<class Type> 87 ContainerListener<Type>::~ContainerListener() {} 88 89 90 template<class Type> 91 Container<Type>::Container(bool ownsItems) 92 : fItems(16), 93 fOwnsItems(ownsItems), 94 fListeners(2) 95 { 96 } 97 98 99 template<class Type> 100 Container<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 114 template<class Type> 115 bool 116 Container<Type>::AddItem(Type* item) 117 { 118 return AddItem(item, CountItems()); 119 } 120 121 122 template<class Type> 123 bool 124 Container<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 143 template<class Type> 144 bool 145 Container<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 156 template<class Type> 157 Type* 158 Container<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 169 template<class Type> 170 void 171 Container<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 192 template<class Type> 193 int32 194 Container<Type>::CountItems() const 195 { 196 return fItems.CountItems(); 197 } 198 199 200 template<class Type> 201 bool 202 Container<Type>::HasItem(Type* item) const 203 { 204 return fItems.HasItem(item); 205 } 206 207 208 template<class Type> 209 int32 210 Container<Type>::IndexOf(Type* item) const 211 { 212 return fItems.IndexOf((void*)item); 213 } 214 215 216 template<class Type> 217 Type* 218 Container<Type>::ItemAt(int32 index) const 219 { 220 return (Type*)fItems.ItemAt(index); 221 } 222 223 224 template<class Type> 225 Type* 226 Container<Type>::ItemAtFast(int32 index) const 227 { 228 return (Type*)fItems.ItemAtFast(index); 229 } 230 231 232 // #pragma mark - 233 234 235 template<class Type> 236 bool 237 Container<Type>::AddListener(ContainerListener<Type>* listener) 238 { 239 if (listener && !fListeners.HasItem(listener)) 240 return fListeners.AddItem(listener); 241 return false; 242 } 243 244 245 template<class Type> 246 bool 247 Container<Type>::RemoveListener(ContainerListener<Type>* listener) 248 { 249 return fListeners.RemoveItem(listener); 250 } 251 252 253 // #pragma mark - 254 255 256 template<class Type> 257 void 258 Container<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 270 template<class Type> 271 void 272 Container<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