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