1/*
2 * Copyright 2006, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stephan Aßmus <superstippi@gmx.de>
7 */
8
9#include "OptionProperty.h"
10
11#include <new>
12#include <stdio.h>
13#include <stdlib.h>
14
15#include <ByteOrder.h>
16#include <Message.h>
17
18using std::nothrow;
19
20// constructor
21OptionProperty::OptionProperty(uint32 identifier)
22	: Property(identifier),
23	  fOptions(4),
24	  fCurrentOptionID(-1)
25{
26}
27
28// copy constructor
29OptionProperty::OptionProperty(const OptionProperty& other)
30	: Property(other),
31	  fOptions(4),
32	  fCurrentOptionID(other.fCurrentOptionID)
33{
34	// clone the actual options
35	int32 count = other.fOptions.CountItems();
36	for (int32 i = 0; i < count; i++) {
37		option* o = (option*)(other.fOptions.ItemAtFast(i));
38		option* clone = new (nothrow) option;
39		if (!clone || !fOptions.AddItem(clone)) {
40			delete clone;
41			break;
42		}
43		clone->id = o->id;
44		clone->name = o->name;
45	}
46}
47
48// archive constructor
49OptionProperty::OptionProperty(BMessage* archive)
50	: Property(archive),
51	  fOptions(4),
52	  fCurrentOptionID(-1)
53{
54	if (!archive)
55		return;
56
57	if (archive->FindInt32("option", &fCurrentOptionID) < B_OK)
58		fCurrentOptionID = -1;
59}
60
61// destrucor
62OptionProperty::~OptionProperty()
63{
64	int32 count = fOptions.CountItems();
65	for (int32 i = 0; i < count; i++)
66		delete (option*)fOptions.ItemAtFast(i);
67}
68
69// #pragma mark -
70
71// Archive
72status_t
73OptionProperty::Archive(BMessage* into, bool deep) const
74{
75	status_t status = Property::Archive(into, deep);
76
77	if (status >= B_OK)
78		status = into->AddInt32("option", fCurrentOptionID);
79
80	// finish off
81	if (status >= B_OK)
82		status = into->AddString("class", "OptionProperty");
83
84	return status;
85}
86
87// Instantiate
88BArchivable*
89OptionProperty::Instantiate(BMessage* archive)
90{
91	if (validate_instantiation(archive, "OptionProperty"))
92		return new (nothrow) OptionProperty(archive);
93	return NULL;
94}
95
96// #pragma mark -
97
98// Clone
99Property*
100OptionProperty::Clone() const
101{
102	return new (nothrow) OptionProperty(*this);
103}
104
105// Type
106type_code
107OptionProperty::Type() const
108{
109	// NOTE: not a Be defined type (those are upper case)
110	return 'optn';
111}
112
113// SetValue
114bool
115OptionProperty::SetValue(const char* value)
116{
117	// try to find option by name
118	int32 count = fOptions.CountItems();
119	for (int32 i = 0; i < count; i++) {
120		option* o = (option*)fOptions.ItemAtFast(i);
121		if (strcmp(o->name.String(), value) == 0) {
122			return SetCurrentOptionID(o->id);
123		}
124	}
125
126	// try to find option by id
127	int32 id = atoi(value);
128	if (id < 0)
129		return false;
130
131	for (int32 i = 0; i < count; i++) {
132		option* o = (option*)fOptions.ItemAtFast(i);
133		if (o->id == id) {
134			return SetCurrentOptionID(o->id);
135		}
136	}
137	return false;
138}
139
140// SetValue
141bool
142OptionProperty::SetValue(const Property* other)
143{
144	const OptionProperty* optOther = dynamic_cast<const OptionProperty*>(other);
145	if (optOther) {
146		return SetCurrentOptionID(optOther->CurrentOptionID());
147	}
148	return false;
149}
150
151// GetValue
152void
153OptionProperty::GetValue(BString& string)
154{
155	if (!GetCurrentOption(&string))
156		string << fCurrentOptionID;
157}
158
159// MakeAnimatable
160bool
161OptionProperty::MakeAnimatable(bool animatable)
162{
163	return false;
164}
165
166// #pragma mark -
167
168// AddOption
169void
170OptionProperty::AddOption(int32 id, const char* name)
171{
172	if (!name)
173		return;
174
175	if (option* o = new (nothrow) option) {
176		o->id = id;
177		o->name = name;
178		fOptions.AddItem((void*)o);
179	}
180}
181
182// CurrentOptionID
183int32
184OptionProperty::CurrentOptionID() const
185{
186	return fCurrentOptionID;
187}
188
189// SetCurrentOptionID
190bool
191OptionProperty::SetCurrentOptionID(int32 id)
192{
193	if (fCurrentOptionID != id) {
194		fCurrentOptionID = id;
195		return true;
196	}
197	return false;
198}
199
200// GetOption
201bool
202OptionProperty::GetOption(int32 index, BString* string, int32* id) const
203{
204	if (option* o = (option*)fOptions.ItemAt(index)) {
205		*id = o->id;
206		*string = o->name;
207		return true;
208	} else {
209		*id = -1;
210		*string = "";
211		return false;
212	}
213}
214
215// GetCurrentOption
216bool
217OptionProperty::GetCurrentOption(BString* string) const
218{
219	for (int32 i = 0; option* o = (option*)fOptions.ItemAt(i); i++) {
220		if (o->id == fCurrentOptionID) {
221			*string = o->name;
222			return true;
223		}
224	}
225uint32 current = B_HOST_TO_BENDIAN_INT32(fCurrentOptionID);
226printf("OptionProperty::GetCurrentOption() - "
227	"did not find option %.4s!!\n", (char*)&current);
228	return false;
229}
230
231// SetOptionAtOffset
232bool
233OptionProperty::SetOptionAtOffset(int32 indexOffset)
234{
235	// NOTE: used by the Property editor GUI
236	if (fOptions.CountItems() > 1) {
237		int32 index = -1;
238		for (int32 i = 0; option* o = (option*)fOptions.ItemAt(i); i++) {
239			if (o->id == fCurrentOptionID) {
240				index = i;
241			}
242		}
243		if (index >= 0) {
244			// offset index
245			index += indexOffset;
246			// keep index in range by wrapping arround
247			if (index >= fOptions.CountItems())
248				index = 0;
249			if (index < 0)
250				index = fOptions.CountItems() - 1;
251			if (option* o = (option*)fOptions.ItemAt(index)) {
252				SetCurrentOptionID(o->id);
253				return true;
254			}
255		}
256	}
257	return false;
258}
259
260
261
262