xref: /haiku/src/libs/icon/generic/Container.h (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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