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 "Property.h"
10
11#include <new>
12#include <stdio.h>
13#include <stdlib.h>
14#include <strings.h>
15
16#include <Message.h>
17
18#include "support.h"
19
20using std::nothrow;
21
22// constructor
23Property::Property(uint32 identifier)
24	: fIdentifier(identifier),
25	  fEditable(true)
26{
27}
28
29// constructor
30Property::Property(const Property& other)
31	: fIdentifier(other.fIdentifier),
32	  fEditable(other.fEditable)
33{
34}
35
36// constructor
37Property::Property(BMessage* archive)
38	: fIdentifier(0),
39	  fEditable(true)
40{
41	if (!archive)
42		return;
43
44	if (archive->FindInt32("id", (int32*)&fIdentifier) < B_OK)
45		fIdentifier = 0;
46	if (archive->FindBool("editable", &fEditable) < B_OK)
47		fEditable = true;
48}
49
50// destructor
51Property::~Property()
52{
53}
54
55// Archive
56status_t
57Property::Archive(BMessage* into, bool deep) const
58{
59	status_t ret = BArchivable::Archive(into, deep);
60
61	if (ret == B_OK)
62		ret = into->AddInt32("id", fIdentifier);
63
64	if (ret == B_OK)
65		ret = into->AddBool("editable", fEditable);
66
67	// finish off
68	if (ret >= B_OK)
69		ret = into->AddString("class", "Property");
70
71	return ret;
72}
73
74// #pragma mark -
75
76// InterpolateTo
77bool
78Property::InterpolateTo(const Property* other, float scale)
79{
80	// some properties don't support this
81	return false;
82}
83
84// SetEditable
85void
86Property::SetEditable(bool editable)
87{
88	fEditable = editable;
89}
90
91// #pragma mark -
92
93// constructor
94IntProperty::IntProperty(uint32 identifier, int32 value,
95						 int32 min, int32 max)
96	: Property(identifier),
97	  fValue(value),
98	  fMin(min),
99	  fMax(max)
100{
101}
102
103// constructor
104IntProperty::IntProperty(const IntProperty& other)
105	: Property(other),
106	  fValue(other.fValue),
107	  fMin(other.fMin),
108	  fMax(other.fMax)
109{
110}
111
112// constructor
113IntProperty::IntProperty(BMessage* archive)
114	: Property(archive),
115	  fValue(0),
116	  fMin(0),
117	  fMax(0)
118{
119	if (!archive)
120		return;
121
122	if (archive->FindInt32("value", &fValue) < B_OK)
123		fValue = 0;
124	if (archive->FindInt32("min", &fMin) < B_OK)
125		fMin = 0;
126	if (archive->FindInt32("max", &fMax) < B_OK)
127		fMax = 0;
128}
129
130// destructor
131IntProperty::~IntProperty()
132{
133}
134
135// Archive
136status_t
137IntProperty::Archive(BMessage* into, bool deep) const
138{
139	status_t ret = Property::Archive(into, deep);
140
141	if (ret >= B_OK)
142		ret = into->AddInt32("value", fValue);
143	if (ret >= B_OK)
144		ret = into->AddInt32("min", fMin);
145	if (ret >= B_OK)
146		ret = into->AddInt32("max", fMax);
147
148	// finish off
149	if (ret >= B_OK)
150		ret = into->AddString("class", "IntProperty");
151
152	return ret;
153}
154
155// Instantiate
156BArchivable*
157IntProperty::Instantiate(BMessage* archive)
158{
159	if (validate_instantiation(archive, "IntProperty"))
160		return new IntProperty(archive);
161
162	return NULL;
163}
164
165// Clone
166Property*
167IntProperty::Clone() const
168{
169	return new IntProperty(*this);
170}
171
172// SetValue
173bool
174IntProperty::SetValue(const char* value)
175{
176	return SetValue(atoi(value));
177}
178
179// SetValue
180bool
181IntProperty::SetValue(const Property* other)
182{
183	const IntProperty* i = dynamic_cast<const IntProperty*>(other);
184	if (i) {
185		return SetValue(i->Value());
186	}
187	return false;
188}
189
190// GetValue
191void
192IntProperty::GetValue(BString& string)
193{
194	string << fValue;
195}
196
197// InterpolateTo
198bool
199IntProperty::InterpolateTo(const Property* other, float scale)
200{
201	const IntProperty* i = dynamic_cast<const IntProperty*>(other);
202	if (i) {
203		return SetValue(fValue + (int32)((float)(i->Value()
204												 - fValue) * scale + 0.5));
205	}
206	return false;
207}
208
209// SetValue
210bool
211IntProperty::SetValue(int32 value)
212{
213	// truncate
214	if (value < fMin)
215		value = fMin;
216	if (value > fMax)
217		value = fMax;
218
219	if (value != fValue) {
220		fValue = value;
221		return true;
222	}
223	return false;
224}
225
226// #pragma mark -
227
228// constructor
229FloatProperty::FloatProperty(uint32 identifier, float value,
230							 float min, float max)
231	: Property(identifier),
232	  fValue(value),
233	  fMin(min),
234	  fMax(max)
235{
236}
237
238// constructor
239FloatProperty::FloatProperty(const FloatProperty& other)
240	: Property(other),
241	  fValue(other.fValue),
242	  fMin(other.fMin),
243	  fMax(other.fMax)
244{
245}
246
247// constructor
248FloatProperty::FloatProperty(BMessage* archive)
249	: Property(archive),
250	  fValue(0.0),
251	  fMin(0.0),
252	  fMax(0.0)
253{
254	if (!archive)
255		return;
256
257	if (archive->FindFloat("value", &fValue) < B_OK)
258		fValue = 0.0;
259	if (archive->FindFloat("min", &fMin) < B_OK)
260		fMin = 0.0;
261	if (archive->FindFloat("max", &fMax) < B_OK)
262		fMax = 0.0;
263}
264
265// destructor
266FloatProperty::~FloatProperty()
267{
268}
269
270// Archive
271status_t
272FloatProperty::Archive(BMessage* into, bool deep) const
273{
274	status_t ret = Property::Archive(into, deep);
275
276	if (ret >= B_OK)
277		ret = into->AddFloat("value", fValue);
278	if (ret >= B_OK)
279		ret = into->AddFloat("min", fMin);
280	if (ret >= B_OK)
281		ret = into->AddFloat("max", fMax);
282
283	// finish off
284	if (ret >= B_OK)
285		ret = into->AddString("class", "FloatProperty");
286
287	return ret;
288}
289
290// Instantiate
291BArchivable*
292FloatProperty::Instantiate(BMessage* archive)
293{
294	if (validate_instantiation(archive, "FloatProperty"))
295		return new FloatProperty(archive);
296
297	return NULL;
298}
299
300// Clone
301Property*
302FloatProperty::Clone() const
303{
304	return new FloatProperty(*this);
305}
306
307// SetValue
308bool
309FloatProperty::SetValue(const char* value)
310{
311	return SetValue(atof(value));
312}
313
314// SetValue
315bool
316FloatProperty::SetValue(const Property* other)
317{
318	const FloatProperty* f = dynamic_cast<const FloatProperty*>(other);
319	if (f) {
320		return SetValue(f->Value());
321	}
322	return false;
323}
324
325// GetValue
326void
327FloatProperty::GetValue(BString& string)
328{
329	append_float(string, fValue, 4);
330}
331
332// InterpolateTo
333bool
334FloatProperty::InterpolateTo(const Property* other, float scale)
335{
336	const FloatProperty* f = dynamic_cast<const FloatProperty*>(other);
337	if (f) {
338		return SetValue(fValue + (f->Value() - fValue) * scale);
339	}
340	return false;
341}
342
343// SetValue
344bool
345FloatProperty::SetValue(float value)
346{
347	// truncate
348	if (value < fMin)
349		value = fMin;
350	if (value > fMax)
351		value = fMax;
352
353	if (value != fValue) {
354		fValue = value;
355		return true;
356	}
357	return false;
358}
359
360// #pragma mark -
361
362// constructor
363UInt8Property::UInt8Property(uint32 identifier, uint8 value)
364	: Property(identifier),
365	  fValue(value)
366{
367}
368
369// constructor
370UInt8Property::UInt8Property(const UInt8Property& other)
371	: Property(other),
372	  fValue(other.fValue)
373{
374}
375
376// constructor
377UInt8Property::UInt8Property(BMessage* archive)
378	: Property(archive),
379	  fValue(0)
380{
381	if (!archive)
382		return;
383
384	if (archive->FindInt8("value", (int8*)&fValue) < B_OK)
385		fValue = 0;
386}
387
388// destructor
389UInt8Property::~UInt8Property()
390{
391}
392
393// Archive
394status_t
395UInt8Property::Archive(BMessage* into, bool deep) const
396{
397	status_t ret = Property::Archive(into, deep);
398
399	if (ret >= B_OK)
400		ret = into->AddInt8("value", fValue);
401
402	// finish off
403	if (ret >= B_OK)
404		ret = into->AddString("class", "UInt8Property");
405
406	return ret;
407}
408
409// Instantiate
410BArchivable*
411UInt8Property::Instantiate(BMessage* archive)
412{
413	if (validate_instantiation(archive, "UInt8Property"))
414		return new UInt8Property(archive);
415
416	return NULL;
417}
418
419// Clone
420Property*
421UInt8Property::Clone() const
422{
423	return new UInt8Property(*this);
424}
425
426// SetValue
427bool
428UInt8Property::SetValue(const char* value)
429{
430	return SetValue((uint8)max_c(0, min_c(255, atoi(value))));
431}
432
433// SetValue
434bool
435UInt8Property::SetValue(const Property* other)
436{
437	const UInt8Property* u = dynamic_cast<const UInt8Property*>(other);
438	if (u) {
439		return SetValue(u->Value());
440	}
441	return false;
442}
443
444// GetValue
445void
446UInt8Property::GetValue(BString& string)
447{
448	string << fValue;
449}
450
451// InterpolateTo
452bool
453UInt8Property::InterpolateTo(const Property* other, float scale)
454{
455	const UInt8Property* u = dynamic_cast<const UInt8Property*>(other);
456	if (u) {
457		return SetValue(fValue + (uint8)((float)(u->Value()
458												 - fValue) * scale + 0.5));
459	}
460	return false;
461}
462
463// SetValue
464bool
465UInt8Property::SetValue(uint8 value)
466{
467	if (value != fValue) {
468		fValue = value;
469		return true;
470	}
471	return false;
472}
473
474// #pragma mark -
475
476// constructor
477BoolProperty::BoolProperty(uint32 identifier, bool value)
478	: Property(identifier),
479	  fValue(value)
480{
481}
482
483// constructor
484BoolProperty::BoolProperty(const BoolProperty& other)
485	: Property(other),
486	  fValue(other.fValue)
487{
488}
489
490// constructor
491BoolProperty::BoolProperty(BMessage* archive)
492	: Property(archive),
493	  fValue(false)
494{
495	if (!archive)
496		return;
497
498	if (archive->FindBool("value", &fValue) < B_OK)
499		fValue = false;
500}
501
502// destructor
503BoolProperty::~BoolProperty()
504{
505}
506
507// Archive
508status_t
509BoolProperty::Archive(BMessage* into, bool deep) const
510{
511	status_t ret = Property::Archive(into, deep);
512
513	if (ret >= B_OK)
514		ret = into->AddBool("value", fValue);
515
516	// finish off
517	if (ret >= B_OK)
518		ret = into->AddString("class", "BoolProperty");
519
520	return ret;
521}
522
523// Instantiate
524BArchivable*
525BoolProperty::Instantiate(BMessage* archive)
526{
527	if (validate_instantiation(archive, "BoolProperty"))
528		return new BoolProperty(archive);
529
530	return NULL;
531}
532
533// Clone
534Property*
535BoolProperty::Clone() const
536{
537	return new BoolProperty(*this);
538}
539
540// SetValue
541bool
542BoolProperty::SetValue(const char* value)
543{
544	bool v;
545	if (strcasecmp(value, "true") == 0)
546		v = true;
547	else if (strcasecmp(value, "on") == 0)
548		v = true;
549	else
550		v = (bool)atoi(value);
551
552	return SetValue(v);
553}
554
555// SetValue
556bool
557BoolProperty::SetValue(const Property* other)
558{
559	const BoolProperty* b = dynamic_cast<const BoolProperty*>(other);
560	if (b) {
561		return SetValue(b->Value());
562	}
563	return false;
564}
565
566// GetValue
567void
568BoolProperty::GetValue(BString& string)
569{
570	if (fValue)
571		string << "on";
572	else
573		string << "off";
574}
575
576// InterpolateTo
577bool
578BoolProperty::InterpolateTo(const Property* other, float scale)
579{
580	const BoolProperty* b = dynamic_cast<const BoolProperty*>(other);
581	if (b) {
582		if (scale >= 0.5)
583			return SetValue(b->Value());
584	}
585	return false;
586}
587
588// SetValue
589bool
590BoolProperty::SetValue(bool value)
591{
592	if (value != fValue) {
593		fValue = value;
594		return true;
595	}
596	return false;
597}
598
599// #pragma mark -
600
601// constructor
602StringProperty::StringProperty(uint32 identifier, const char* value)
603	: Property(identifier),
604	  fValue(value)
605{
606}
607
608// constructor
609StringProperty::StringProperty(const StringProperty& other)
610	: Property(other),
611	  fValue(other.fValue)
612{
613}
614
615// constructor
616StringProperty::StringProperty(BMessage* archive)
617	: Property(archive),
618	  fValue()
619{
620	if (!archive)
621		return;
622
623	if (archive->FindString("value", &fValue) < B_OK)
624		fValue = "";
625}
626
627// destructor
628StringProperty::~StringProperty()
629{
630}
631
632// Archive
633status_t
634StringProperty::Archive(BMessage* into, bool deep) const
635{
636	status_t ret = Property::Archive(into, deep);
637
638	if (ret >= B_OK)
639		ret = into->AddString("value", fValue);
640
641	// finish off
642	if (ret >= B_OK)
643		ret = into->AddString("class", "StringProperty");
644
645	return ret;
646}
647
648// Instantiate
649BArchivable*
650StringProperty::Instantiate(BMessage* archive)
651{
652	if (validate_instantiation(archive, "StringProperty"))
653		return new StringProperty(archive);
654
655	return NULL;
656}
657
658// Clone
659Property*
660StringProperty::Clone() const
661{
662	return new StringProperty(*this);
663}
664
665// SetValue
666bool
667StringProperty::SetValue(const char* value)
668{
669	BString t(value);
670	if (fValue != t) {
671		fValue = t;
672		return true;
673	}
674	return false;
675}
676
677// SetValue
678bool
679StringProperty::SetValue(const Property* other)
680{
681	const StringProperty* s = dynamic_cast<const StringProperty*>(other);
682	if (s) {
683		return SetValue(s->Value());
684	}
685	return false;
686}
687
688// GetValue
689void
690StringProperty::GetValue(BString& string)
691{
692	string << fValue;
693}
694
695