1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7#include "ImageListView.h"
8
9#include <stdio.h>
10
11#include <new>
12
13#include <Looper.h>
14#include <Message.h>
15
16#include <AutoLocker.h>
17#include <ObjectList.h>
18
19#include "GuiSettingsUtils.h"
20#include "table/TableColumns.h"
21#include "Tracing.h"
22
23
24enum {
25	MSG_SYNC_IMAGE_LIST	= 'sytl'
26};
27
28
29// #pragma mark - ImagesTableModel
30
31
32class ImageListView::ImagesTableModel : public TableModel {
33public:
34	ImagesTableModel(Team* team)
35		:
36		fTeam(team)
37	{
38		Update();
39	}
40
41	~ImagesTableModel()
42	{
43		fTeam = NULL;
44		Update();
45	}
46
47	bool Update()
48	{
49		if (fTeam == NULL) {
50			for (int32 i = 0; Image* image = fImages.ItemAt(i); i++)
51				image->ReleaseReference();
52			fImages.MakeEmpty();
53
54			return true;
55		}
56
57		AutoLocker<Team> locker(fTeam);
58
59		ImageList::ConstIterator it = fTeam->Images().GetIterator();
60		Image* newImage = it.Next();
61		int32 index = 0;
62
63		// remove no longer existing images
64		while (Image* oldImage = fImages.ItemAt(index)) {
65			if (oldImage == newImage) {
66				index++;
67				newImage = it.Next();
68			} else {
69				// TODO: Not particularly efficient!
70				fImages.RemoveItemAt(index);
71				oldImage->ReleaseReference();
72				NotifyRowsRemoved(index, 1);
73			}
74		}
75
76		// add new images
77		int32 countBefore = fImages.CountItems();
78		while (newImage != NULL) {
79			if (!fImages.AddItem(newImage))
80				return false;
81
82			newImage->AcquireReference();
83			newImage = it.Next();
84		}
85
86		int32 count = fImages.CountItems();
87		if (count > countBefore)
88			NotifyRowsAdded(countBefore, count - countBefore);
89
90		return true;
91	}
92
93	virtual int32 CountColumns() const
94	{
95		return 2;
96	}
97
98	virtual int32 CountRows() const
99	{
100		return fImages.CountItems();
101	}
102
103	virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value)
104	{
105		Image* image = fImages.ItemAt(rowIndex);
106		if (image == NULL)
107			return false;
108
109		switch (columnIndex) {
110			case 0:
111				value.SetTo(image->ID());
112				return true;
113			case 1:
114				value.SetTo(image->Name(), B_VARIANT_DONT_COPY_DATA);
115				return true;
116			default:
117				return false;
118		}
119	}
120
121	Image* ImageAt(int32 index) const
122	{
123		return fImages.ItemAt(index);
124	}
125
126private:
127	Team*				fTeam;
128	BObjectList<Image>	fImages;
129};
130
131
132// #pragma mark - ImageListView
133
134
135ImageListView::ImageListView(Team* team, Listener* listener)
136	:
137	BGroupView(B_VERTICAL),
138	fTeam(team),
139	fImage(NULL),
140	fImagesTable(NULL),
141	fImagesTableModel(NULL),
142	fListener(listener)
143{
144	SetName("Images");
145
146	fTeam->AddListener(this);
147}
148
149
150ImageListView::~ImageListView()
151{
152	SetImage(NULL);
153	fTeam->RemoveListener(this);
154	fImagesTable->SetTableModel(NULL);
155	delete fImagesTableModel;
156}
157
158
159/*static*/ ImageListView*
160ImageListView::Create(Team* team, Listener* listener)
161{
162	ImageListView* self = new ImageListView(team, listener);
163
164	try {
165		self->_Init();
166	} catch (...) {
167		delete self;
168		throw;
169	}
170
171	return self;
172}
173
174
175void
176ImageListView::UnsetListener()
177{
178	fListener = NULL;
179}
180
181
182void
183ImageListView::SetImage(Image* image)
184{
185	if (image == fImage)
186		return;
187
188	TRACE_GUI("ImageListView::SetImage(%p)\n", image);
189
190	if (fImage != NULL)
191		fImage->ReleaseReference();
192
193	fImage = image;
194
195	if (fImage != NULL) {
196		fImage->AcquireReference();
197
198		for (int32 i = 0; Image* other = fImagesTableModel->ImageAt(i); i++) {
199			if (fImage == other) {
200				fImagesTable->SelectRow(i, false);
201
202				TRACE_GUI("ImageListView::SetImage() done\n");
203				return;
204			}
205		}
206	}
207
208	fImagesTable->DeselectAllRows();
209
210	TRACE_GUI("ImageListView::SetImage() done\n");
211}
212
213
214void
215ImageListView::MessageReceived(BMessage* message)
216{
217	switch (message->what) {
218		case MSG_SYNC_IMAGE_LIST:
219			if (fImagesTableModel != NULL)
220				fImagesTableModel->Update();
221			break;
222		default:
223			BGroupView::MessageReceived(message);
224			break;
225	}
226}
227
228
229void
230ImageListView::LoadSettings(const BMessage& settings)
231{
232	BMessage tableSettings;
233	if (settings.FindMessage("imagesTable", &tableSettings) == B_OK) {
234		GuiSettingsUtils::UnarchiveTableSettings(tableSettings,
235			fImagesTable);
236	}
237}
238
239
240status_t
241ImageListView::SaveSettings(BMessage& settings)
242{
243	settings.MakeEmpty();
244
245	BMessage tableSettings;
246	status_t result = GuiSettingsUtils::ArchiveTableSettings(tableSettings,
247		fImagesTable);
248	if (result == B_OK)
249		result = settings.AddMessage("imagesTable", &tableSettings);
250
251	return result;
252}
253
254
255void
256ImageListView::ImageAdded(const Team::ImageEvent& event)
257{
258	Looper()->PostMessage(MSG_SYNC_IMAGE_LIST, this);
259}
260
261
262void
263ImageListView::ImageRemoved(const Team::ImageEvent& event)
264{
265	Looper()->PostMessage(MSG_SYNC_IMAGE_LIST, this);
266}
267
268
269void
270ImageListView::TableSelectionChanged(Table* table)
271{
272	if (fListener == NULL)
273		return;
274
275	Image* image = NULL;
276	if (fImagesTableModel != NULL) {
277		TableSelectionModel* selectionModel = table->SelectionModel();
278		image = fImagesTableModel->ImageAt(selectionModel->RowAt(0));
279	}
280
281	fListener->ImageSelectionChanged(image);
282}
283
284
285void
286ImageListView::_Init()
287{
288	fImagesTable = new Table("images list", 0, B_FANCY_BORDER);
289	AddChild(fImagesTable->ToView());
290
291	// columns
292	fImagesTable->AddColumn(new Int32TableColumn(0, "ID", 40, 20, 1000,
293		B_TRUNCATE_MIDDLE, B_ALIGN_RIGHT));
294	fImagesTable->AddColumn(new StringTableColumn(1, "Name", 80, 40, 1000,
295		B_TRUNCATE_END, B_ALIGN_LEFT));
296
297	fImagesTable->AddTableListener(this);
298
299	fImagesTableModel = new ImagesTableModel(fTeam);
300	fImagesTable->SetTableModel(fImagesTableModel);
301	fImagesTable->ResizeAllColumnsToPreferred();
302}
303
304
305// #pragma mark - Listener
306
307
308ImageListView::Listener::~Listener()
309{
310}
311