root/src/apps/icon-o-matic/generic/property/Property.cpp
/*
 * Copyright 2006, Haiku.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Stephan Aßmus <superstippi@gmx.de>
 */

#include "Property.h"

#include <new>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

#include <Message.h>

#include "support.h"

using std::nothrow;

// constructor
Property::Property(uint32 identifier)
        : fIdentifier(identifier),
          fEditable(true)
{
}

// constructor
Property::Property(const Property& other)
        : fIdentifier(other.fIdentifier),
          fEditable(other.fEditable)
{
}

// constructor
Property::Property(BMessage* archive)
        : fIdentifier(0),
          fEditable(true)
{
        if (!archive)
                return;

        if (archive->FindInt32("id", (int32*)&fIdentifier) < B_OK)
                fIdentifier = 0;
        if (archive->FindBool("editable", &fEditable) < B_OK)
                fEditable = true;
}

// destructor
Property::~Property()
{
}

// Archive
status_t
Property::Archive(BMessage* into, bool deep) const
{
        status_t ret = BArchivable::Archive(into, deep);

        if (ret == B_OK)
                ret = into->AddInt32("id", fIdentifier);

        if (ret == B_OK)
                ret = into->AddBool("editable", fEditable);

        // finish off
        if (ret >= B_OK)
                ret = into->AddString("class", "Property");

        return ret;
}

// #pragma mark -

// InterpolateTo
bool
Property::InterpolateTo(const Property* other, float scale)
{
        // some properties don't support this
        return false;
}

// SetEditable
void
Property::SetEditable(bool editable)
{
        fEditable = editable;
}

// #pragma mark -

// constructor
IntProperty::IntProperty(uint32 identifier, int32 value,
                                                 int32 min, int32 max)
        : Property(identifier),
          fValue(value),
          fMin(min),
          fMax(max)
{
}

// constructor
IntProperty::IntProperty(const IntProperty& other)
        : Property(other),
          fValue(other.fValue),
          fMin(other.fMin),
          fMax(other.fMax)
{
}

// constructor
IntProperty::IntProperty(BMessage* archive)
        : Property(archive),
          fValue(0),
          fMin(0),
          fMax(0)
{
        if (!archive)
                return;

        if (archive->FindInt32("value", &fValue) < B_OK)
                fValue = 0;
        if (archive->FindInt32("min", &fMin) < B_OK)
                fMin = 0;
        if (archive->FindInt32("max", &fMax) < B_OK)
                fMax = 0;
}

// destructor
IntProperty::~IntProperty()
{
}

// Archive
status_t
IntProperty::Archive(BMessage* into, bool deep) const
{
        status_t ret = Property::Archive(into, deep);

        if (ret >= B_OK)
                ret = into->AddInt32("value", fValue);
        if (ret >= B_OK)
                ret = into->AddInt32("min", fMin);
        if (ret >= B_OK)
                ret = into->AddInt32("max", fMax);

        // finish off
        if (ret >= B_OK)
                ret = into->AddString("class", "IntProperty");

        return ret;
}

// Instantiate
BArchivable*
IntProperty::Instantiate(BMessage* archive)
{
        if (validate_instantiation(archive, "IntProperty"))
                return new IntProperty(archive);

        return NULL;
}

// Clone
Property*
IntProperty::Clone() const
{
        return new IntProperty(*this);
}

// SetValue
bool
IntProperty::SetValue(const char* value)
{
        return SetValue(atoi(value));
}

// SetValue
bool
IntProperty::SetValue(const Property* other)
{
        const IntProperty* i = dynamic_cast<const IntProperty*>(other);
        if (i) {
                return SetValue(i->Value());
        }
        return false;
}

// GetValue
void
IntProperty::GetValue(BString& string)
{
        string << fValue;
}

// InterpolateTo
bool
IntProperty::InterpolateTo(const Property* other, float scale)
{
        const IntProperty* i = dynamic_cast<const IntProperty*>(other);
        if (i) {
                return SetValue(fValue + (int32)((float)(i->Value()
                                                                                                 - fValue) * scale + 0.5));
        }
        return false;
}

// SetValue
bool
IntProperty::SetValue(int32 value)
{
        // truncate
        if (value < fMin)
                value = fMin;
        if (value > fMax)
                value = fMax;

        if (value != fValue) {
                fValue = value;
                return true;
        }
        return false;
}

// #pragma mark -

// constructor
FloatProperty::FloatProperty(uint32 identifier, float value,
                                                         float min, float max)
        : Property(identifier),
          fValue(value),
          fMin(min),
          fMax(max)
{
}

// constructor
FloatProperty::FloatProperty(const FloatProperty& other)
        : Property(other),
          fValue(other.fValue),
          fMin(other.fMin),
          fMax(other.fMax)
{
}

// constructor
FloatProperty::FloatProperty(BMessage* archive)
        : Property(archive),
          fValue(0.0),
          fMin(0.0),
          fMax(0.0)
{
        if (!archive)
                return;

        if (archive->FindFloat("value", &fValue) < B_OK)
                fValue = 0.0;
        if (archive->FindFloat("min", &fMin) < B_OK)
                fMin = 0.0;
        if (archive->FindFloat("max", &fMax) < B_OK)
                fMax = 0.0;
}

// destructor
FloatProperty::~FloatProperty()
{
}

// Archive
status_t
FloatProperty::Archive(BMessage* into, bool deep) const
{
        status_t ret = Property::Archive(into, deep);

        if (ret >= B_OK)
                ret = into->AddFloat("value", fValue);
        if (ret >= B_OK)
                ret = into->AddFloat("min", fMin);
        if (ret >= B_OK)
                ret = into->AddFloat("max", fMax);

        // finish off
        if (ret >= B_OK)
                ret = into->AddString("class", "FloatProperty");

        return ret;
}

// Instantiate
BArchivable*
FloatProperty::Instantiate(BMessage* archive)
{
        if (validate_instantiation(archive, "FloatProperty"))
                return new FloatProperty(archive);

        return NULL;
}

// Clone
Property*
FloatProperty::Clone() const
{
        return new FloatProperty(*this);
}

// SetValue
bool
FloatProperty::SetValue(const char* value)
{
        return SetValue(atof(value));
}

// SetValue
bool
FloatProperty::SetValue(const Property* other)
{
        const FloatProperty* f = dynamic_cast<const FloatProperty*>(other);
        if (f) {
                return SetValue(f->Value());
        }
        return false;
}

// GetValue
void
FloatProperty::GetValue(BString& string)
{
        append_float(string, fValue, 4);
}

// InterpolateTo
bool
FloatProperty::InterpolateTo(const Property* other, float scale)
{
        const FloatProperty* f = dynamic_cast<const FloatProperty*>(other);
        if (f) {
                return SetValue(fValue + (f->Value() - fValue) * scale);
        }
        return false;
}

// SetValue
bool
FloatProperty::SetValue(float value)
{
        // truncate
        if (value < fMin)
                value = fMin;
        if (value > fMax)
                value = fMax;

        if (value != fValue) {
                fValue = value;
                return true;
        }
        return false;
}

// #pragma mark -

// constructor
UInt8Property::UInt8Property(uint32 identifier, uint8 value)
        : Property(identifier),
          fValue(value)
{
}

// constructor
UInt8Property::UInt8Property(const UInt8Property& other)
        : Property(other),
          fValue(other.fValue)
{
}

// constructor
UInt8Property::UInt8Property(BMessage* archive)
        : Property(archive),
          fValue(0)
{
        if (!archive)
                return;

        if (archive->FindInt8("value", (int8*)&fValue) < B_OK)
                fValue = 0;
}

// destructor
UInt8Property::~UInt8Property()
{
}

// Archive
status_t
UInt8Property::Archive(BMessage* into, bool deep) const
{
        status_t ret = Property::Archive(into, deep);

        if (ret >= B_OK)
                ret = into->AddInt8("value", fValue);

        // finish off
        if (ret >= B_OK)
                ret = into->AddString("class", "UInt8Property");

        return ret;
}

// Instantiate
BArchivable*
UInt8Property::Instantiate(BMessage* archive)
{
        if (validate_instantiation(archive, "UInt8Property"))
                return new UInt8Property(archive);

        return NULL;
}

// Clone
Property*
UInt8Property::Clone() const
{
        return new UInt8Property(*this);
}

// SetValue
bool
UInt8Property::SetValue(const char* value)
{
        return SetValue((uint8)max_c(0, min_c(255, atoi(value))));
}

// SetValue
bool
UInt8Property::SetValue(const Property* other)
{
        const UInt8Property* u = dynamic_cast<const UInt8Property*>(other);
        if (u) {
                return SetValue(u->Value());
        }
        return false;
}

// GetValue
void
UInt8Property::GetValue(BString& string)
{
        string << fValue;
}

// InterpolateTo
bool
UInt8Property::InterpolateTo(const Property* other, float scale)
{
        const UInt8Property* u = dynamic_cast<const UInt8Property*>(other);
        if (u) {
                return SetValue(fValue + (uint8)((float)(u->Value()
                                                                                                 - fValue) * scale + 0.5));
        }
        return false;
}

// SetValue
bool
UInt8Property::SetValue(uint8 value)
{
        if (value != fValue) {
                fValue = value;
                return true;
        }
        return false;
}

// #pragma mark -

// constructor
BoolProperty::BoolProperty(uint32 identifier, bool value)
        : Property(identifier),
          fValue(value)
{
}

// constructor
BoolProperty::BoolProperty(const BoolProperty& other)
        : Property(other),
          fValue(other.fValue)
{
}

// constructor
BoolProperty::BoolProperty(BMessage* archive)
        : Property(archive),
          fValue(false)
{
        if (!archive)
                return;

        if (archive->FindBool("value", &fValue) < B_OK)
                fValue = false;
}

// destructor
BoolProperty::~BoolProperty()
{
}

// Archive
status_t
BoolProperty::Archive(BMessage* into, bool deep) const
{
        status_t ret = Property::Archive(into, deep);

        if (ret >= B_OK)
                ret = into->AddBool("value", fValue);

        // finish off
        if (ret >= B_OK)
                ret = into->AddString("class", "BoolProperty");

        return ret;
}

// Instantiate
BArchivable*
BoolProperty::Instantiate(BMessage* archive)
{
        if (validate_instantiation(archive, "BoolProperty"))
                return new BoolProperty(archive);

        return NULL;
}

// Clone
Property*
BoolProperty::Clone() const
{
        return new BoolProperty(*this);
}

// SetValue
bool
BoolProperty::SetValue(const char* value)
{
        bool v;
        if (strcasecmp(value, "true") == 0)
                v = true;
        else if (strcasecmp(value, "on") == 0)
                v = true;
        else
                v = (bool)atoi(value);

        return SetValue(v);
}

// SetValue
bool
BoolProperty::SetValue(const Property* other)
{
        const BoolProperty* b = dynamic_cast<const BoolProperty*>(other);
        if (b) {
                return SetValue(b->Value());
        }
        return false;
}

// GetValue
void
BoolProperty::GetValue(BString& string)
{
        if (fValue)
                string << "on";
        else
                string << "off";
}

// InterpolateTo
bool
BoolProperty::InterpolateTo(const Property* other, float scale)
{
        const BoolProperty* b = dynamic_cast<const BoolProperty*>(other);
        if (b) {
                if (scale >= 0.5)
                        return SetValue(b->Value());
        }
        return false;
}

// SetValue
bool
BoolProperty::SetValue(bool value)
{
        if (value != fValue) {
                fValue = value;
                return true;
        }
        return false;
}

// #pragma mark -

// constructor
StringProperty::StringProperty(uint32 identifier, const char* value)
        : Property(identifier),
          fValue(value)
{
}

// constructor
StringProperty::StringProperty(const StringProperty& other)
        : Property(other),
          fValue(other.fValue)
{
}

// constructor
StringProperty::StringProperty(BMessage* archive)
        : Property(archive),
          fValue()
{
        if (!archive)
                return;

        if (archive->FindString("value", &fValue) < B_OK)
                fValue = "";
}

// destructor
StringProperty::~StringProperty()
{
}

// Archive
status_t
StringProperty::Archive(BMessage* into, bool deep) const
{
        status_t ret = Property::Archive(into, deep);

        if (ret >= B_OK)
                ret = into->AddString("value", fValue);

        // finish off
        if (ret >= B_OK)
                ret = into->AddString("class", "StringProperty");

        return ret;
}

// Instantiate
BArchivable*
StringProperty::Instantiate(BMessage* archive)
{
        if (validate_instantiation(archive, "StringProperty"))
                return new StringProperty(archive);

        return NULL;
}

// Clone
Property*
StringProperty::Clone() const
{
        return new StringProperty(*this);
}

// SetValue
bool
StringProperty::SetValue(const char* value)
{
        BString t(value);
        if (fValue != t) {
                fValue = t;
                return true;
        }
        return false;
}

// SetValue
bool
StringProperty::SetValue(const Property* other)
{
        const StringProperty* s = dynamic_cast<const StringProperty*>(other);
        if (s) {
                return SetValue(s->Value());
        }
        return false;
}

// GetValue
void
StringProperty::GetValue(BString& string)
{
        string << fValue;
}