Files
create/src/App/PropertyStandard.cpp

2837 lines
80 KiB
C++

/***************************************************************************
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/math/special_functions/round.hpp>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Reader.h>
#include <Base/Writer.h>
#include <Base/Quantity.h>
#include <Base/Tools.h>
#include "PropertyStandard.h"
#include "Application.h"
#include "Document.h"
#include "DocumentObject.h"
#include "MaterialPy.h"
#include "ObjectIdentifier.h"
using namespace App;
using namespace Base;
using namespace std;
//**************************************************************************
//**************************************************************************
// PropertyInteger
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyInteger , App::Property)
//**************************************************************************
// Construction/Destruction
PropertyInteger::PropertyInteger()
{
_lValue = 0;
}
PropertyInteger::~PropertyInteger()
{
}
//**************************************************************************
// Base class implementer
void PropertyInteger::setValue(long lValue)
{
aboutToSetValue();
_lValue=lValue;
hasSetValue();
}
long PropertyInteger::getValue() const
{
return _lValue;
}
PyObject *PropertyInteger::getPyObject()
{
return Py_BuildValue("l", _lValue);
}
void PropertyInteger::setPyObject(PyObject *value)
{
if (PyLong_Check(value)) {
aboutToSetValue();
_lValue = PyLong_AsLong(value);
hasSetValue();
}
else {
std::string error = std::string("type must be int, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyInteger::Save (Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<Integer value=\"" << _lValue <<"\"/>" << std::endl;
}
void PropertyInteger::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("Integer");
// get the value of my Attribute
setValue(reader.getAttributeAsInteger("value"));
}
Property *PropertyInteger::Copy() const
{
PropertyInteger *p= new PropertyInteger();
p->_lValue = _lValue;
return p;
}
void PropertyInteger::Paste(const Property &from)
{
aboutToSetValue();
_lValue = dynamic_cast<const PropertyInteger&>(from)._lValue;
hasSetValue();
}
void PropertyInteger::setPathValue(const ObjectIdentifier &path, const boost::any &value)
{
verifyPath(path);
if (value.type() == typeid(long))
setValue(boost::any_cast<long>(value));
else if (value.type() == typeid(int))
setValue(boost::any_cast<int>(value));
else if (value.type() == typeid(double))
setValue(boost::math::round(boost::any_cast<double>(value)));
else if (value.type() == typeid(float))
setValue(boost::math::round(boost::any_cast<float>(value)));
else if (value.type() == typeid(Quantity))
setValue(boost::math::round(boost::any_cast<Quantity>(value).getValue()));
else
throw bad_cast();
}
//**************************************************************************
//**************************************************************************
// PropertyPath
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyPath , App::Property)
//**************************************************************************
// Construction/Destruction
PropertyPath::PropertyPath()
{
}
PropertyPath::~PropertyPath()
{
}
//**************************************************************************
// Base class implementer
//**************************************************************************
// Setter/getter for the property
void PropertyPath::setValue(const boost::filesystem::path &Path)
{
aboutToSetValue();
_cValue = Path;
hasSetValue();
}
void PropertyPath::setValue(const char * Path)
{
aboutToSetValue();
#if (BOOST_FILESYSTEM_VERSION == 2)
_cValue = boost::filesystem::path(Path,boost::filesystem::no_check );
//_cValue = boost::filesystem::path(Path,boost::filesystem::native );
//_cValue = boost::filesystem::path(Path,boost::filesystem::windows_name );
#else
_cValue = boost::filesystem::path(Path);
#endif
hasSetValue();
}
const boost::filesystem::path &PropertyPath::getValue(void) const
{
return _cValue;
}
PyObject *PropertyPath::getPyObject()
{
#if (BOOST_FILESYSTEM_VERSION == 2)
std::string str = _cValue.native_file_string();
#else
std::string str = _cValue.string();
#endif
// Returns a new reference, don't increment it!
PyObject *p = PyUnicode_DecodeUTF8(str.c_str(),str.size(),nullptr);
if (!p) throw Base::UnicodeError("UTF8 conversion failure at PropertyPath::getPyObject()");
return p;
}
void PropertyPath::setPyObject(PyObject *value)
{
std::string path;
if (PyUnicode_Check(value)) {
path = PyUnicode_AsUTF8(value);
}
else {
std::string error = std::string("type must be str or unicode, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
// assign the path
setValue(path.c_str());
}
void PropertyPath::Save (Base::Writer &writer) const
{
std::string val = encodeAttribute(_cValue.string());
writer.Stream() << writer.ind() << "<Path value=\"" << val <<"\"/>" << std::endl;
}
void PropertyPath::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("Path");
// get the value of my Attribute
setValue(reader.getAttribute("value"));
}
Property *PropertyPath::Copy() const
{
PropertyPath *p= new PropertyPath();
p->_cValue = _cValue;
return p;
}
void PropertyPath::Paste(const Property &from)
{
aboutToSetValue();
_cValue = dynamic_cast<const PropertyPath&>(from)._cValue;
hasSetValue();
}
unsigned int PropertyPath::getMemSize () const
{
return static_cast<unsigned int>(_cValue.string().size());
}
//**************************************************************************
//**************************************************************************
// PropertyEnumeration
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyEnumeration, App::PropertyInteger)
//**************************************************************************
// Construction/Destruction
PropertyEnumeration::PropertyEnumeration()
{
_editorTypeName = "Gui::PropertyEditor::PropertyEnumItem";
}
PropertyEnumeration::PropertyEnumeration(const App::Enumeration &e)
{
_enum = e;
}
PropertyEnumeration::~PropertyEnumeration()
{
}
void PropertyEnumeration::setEnums(const char **plEnums)
{
// For backward compatibility, if the property container is not attached to
// any document (i.e. its full name starts with '?'), do not notify, or
// else existing code may crash.
bool notify = !boost::starts_with(getFullName(), "?");
if (notify)
aboutToSetValue();
_enum.setEnums(plEnums);
if (notify)
hasSetValue();
}
void PropertyEnumeration::setEnums(const std::vector<std::string> &Enums)
{
// _enum.setEnums() will preserve old value possible, so no need to do it
// here
#if 0
if (_enum.isValid()) {
const std::string &index = getValueAsString();
_enum.setEnums(Enums);
setValue(index.c_str());
} else {
_enum.setEnums(Enums);
}
#else
setEnumVector(Enums);
#endif
}
void PropertyEnumeration::setValue(const char *value)
{
aboutToSetValue();
_enum.setValue(value);
hasSetValue();
}
void PropertyEnumeration::setValue(long value)
{
aboutToSetValue();
_enum.setValue(value);
hasSetValue();
}
void PropertyEnumeration::setValue(const Enumeration &source)
{
aboutToSetValue();
_enum = source;
hasSetValue();
}
long PropertyEnumeration::getValue() const
{
return _enum.getInt();
}
bool PropertyEnumeration::isValue(const char *value) const
{
return _enum.isValue(value);
}
bool PropertyEnumeration::isPartOf(const char *value) const
{
return _enum.contains(value);
}
const char * PropertyEnumeration::getValueAsString() const
{
if (!_enum.isValid())
throw Base::RuntimeError("Cannot get value from invalid enumeration");
return _enum.getCStr();
}
const Enumeration & PropertyEnumeration::getEnum() const
{
return _enum;
}
std::vector<std::string> PropertyEnumeration::getEnumVector() const
{
return _enum.getEnumVector();
}
void PropertyEnumeration::setEnumVector(const std::vector<std::string> &values)
{
// For backward compatibility, if the property container is not attached to
// any document (i.e. its full name starts with '?'), do not notify, or
// else existing code may crash.
bool notify = !boost::starts_with(getFullName(), "?");
if (notify)
aboutToSetValue();
_enum.setEnums(values);
if (notify)
hasSetValue();
}
const char ** PropertyEnumeration::getEnums() const
{
return _enum.getEnums();
}
bool PropertyEnumeration::isValid() const
{
return _enum.isValid();
}
void PropertyEnumeration::Save(Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<Integer value=\"" << _enum.getInt() <<"\"";
if (_enum.isCustom())
writer.Stream() << " CustomEnum=\"true\"";
writer.Stream() << "/>" << std::endl;
if (_enum.isCustom()) {
std::vector<std::string> items = getEnumVector();
writer.Stream() << writer.ind() << "<CustomEnumList count=\"" << items.size() <<"\">" << endl;
writer.incInd();
for(std::vector<std::string>::iterator it = items.begin(); it != items.end(); ++it) {
std::string val = encodeAttribute(*it);
writer.Stream() << writer.ind() << "<Enum value=\"" << val <<"\"/>" << endl;
}
writer.decInd();
writer.Stream() << writer.ind() << "</CustomEnumList>" << endl;
}
}
void PropertyEnumeration::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("Integer");
// get the value of my Attribute
long val = reader.getAttributeAsInteger("value");
aboutToSetValue();
if (reader.hasAttribute("CustomEnum")) {
reader.readElement("CustomEnumList");
int count = reader.getAttributeAsInteger("count");
std::vector<std::string> values(count);
for(int i = 0; i < count; i++) {
reader.readElement("Enum");
values[i] = reader.getAttribute("value");
}
reader.readEndElement("CustomEnumList");
_enum.setEnums(values);
}
if (val < 0) {
// If the enum is empty at this stage do not print a warning
if (_enum.getEnums())
Base::Console().Warning("Enumeration index %d is out of range, ignore it\n", val);
val = getValue();
}
_enum.setValue(val);
hasSetValue();
}
PyObject * PropertyEnumeration::getPyObject()
{
if (!_enum.isValid()) {
// There is legimate use case of having an empty PropertyEnumeration and
// set its enumeration items later. Returning error here cause hasattr()
// to return False even though the property exists.
//
// PyErr_SetString(PyExc_AssertionError, "The enum is empty");
// return 0;
//
Py_Return;
}
return Py_BuildValue("s", getValueAsString());
}
void PropertyEnumeration::setPyObject(PyObject *value)
{
if (PyLong_Check(value)) {
long val = PyLong_AsLong(value);
if (_enum.isValid()) {
aboutToSetValue();
_enum.setValue(val, true);
hasSetValue();
}
return;
}
else if (PyUnicode_Check(value)) {
std::string str = PyUnicode_AsUTF8(value);
if (_enum.contains(str.c_str())) {
aboutToSetValue();
_enum.setValue(str);
hasSetValue();
}
else {
FC_THROWM(Base::ValueError, "'" << str
<< "' is not part of the enumeration in "
<< getFullName());
}
return;
}
else if (PySequence_Check(value)) {
try {
std::vector<std::string> values;
int idx = -1;
Py::Sequence seq(value);
if(seq.size() == 2) {
Py::Object v(seq[0].ptr());
if(!v.isString() && v.isSequence()) {
idx = Py::Int(seq[1].ptr());
seq = v;
}
}
values.resize(seq.size());
for (int i = 0; i < seq.size(); ++i)
values[i] = Py::Object(seq[i].ptr()).as_string();
aboutToSetValue();
_enum.setEnums(values);
if (idx>=0)
_enum.setValue(idx,true);
hasSetValue();
return;
} catch (Py::Exception &) {
Base::PyException e;
e.ReportException();
}
}
FC_THROWM(Base::TypeError, "PropertyEnumeration " << getFullName()
<< " expects type to be int, string, or list(string), or list(list, int)");
}
Property * PropertyEnumeration::Copy() const
{
return new PropertyEnumeration(_enum);
}
void PropertyEnumeration::Paste(const Property &from)
{
const PropertyEnumeration& prop = dynamic_cast<const PropertyEnumeration&>(from);
setValue(prop._enum);
}
void PropertyEnumeration::setPathValue(const ObjectIdentifier &, const boost::any &value)
{
if (value.type() == typeid(int))
setValue(boost::any_cast<int>(value));
else if (value.type() == typeid(long))
setValue(boost::any_cast<long>(value));
else if (value.type() == typeid(double))
setValue(boost::any_cast<double>(value));
else if (value.type() == typeid(float))
setValue(boost::any_cast<float>(value));
else if (value.type() == typeid(short))
setValue(boost::any_cast<short>(value));
else if (value.type() == typeid(std::string))
setValue(boost::any_cast<std::string>(value).c_str());
else if (value.type() == typeid(char*))
setValue(boost::any_cast<char*>(value));
else if (value.type() == typeid(const char*))
setValue(boost::any_cast<const char*>(value));
else {
Base::PyGILStateLocker lock;
Py::Object pyValue = pyObjectFromAny(value);
setPyObject(pyValue.ptr());
}
}
bool PropertyEnumeration::setPyPathValue(const ObjectIdentifier &, const Py::Object &value)
{
setPyObject(value.ptr());
return true;
}
const boost::any PropertyEnumeration::getPathValue(const ObjectIdentifier &path) const
{
std::string p = path.getSubPathStr();
if (p == ".Enum" || p == ".All") {
Base::PyGILStateLocker lock;
Py::Object res;
getPyPathValue(path, res);
return pyObjectToAny(res,false);
}
else if (p == ".String") {
auto v = getValueAsString();
return std::string(v?v:"");
} else
return getValue();
}
bool PropertyEnumeration::getPyPathValue(const ObjectIdentifier &path, Py::Object &r) const
{
std::string p = path.getSubPathStr();
if (p == ".Enum" || p == ".All") {
Base::PyGILStateLocker lock;
Py::Tuple res(_enum.maxValue()+1);
const char **enums = _enum.getEnums();
PropertyString tmp;
for(int i=0;i<=_enum.maxValue();++i) {
tmp.setValue(enums[i]);
res.setItem(i,Py::asObject(tmp.getPyObject()));
}
if(p == ".Enum")
r = res;
else {
Py::Tuple tuple(2);
tuple.setItem(0, res);
tuple.setItem(1, Py::Int(getValue()));
r = tuple;
}
} else if (p == ".String") {
auto v = getValueAsString();
r = Py::String(v?v:"");
} else
r = Py::Int(getValue());
return true;
}
//**************************************************************************
//**************************************************************************
// PropertyIntegerConstraint
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyIntegerConstraint, App::PropertyInteger)
//**************************************************************************
// Construction/Destruction
PropertyIntegerConstraint::PropertyIntegerConstraint()
: _ConstStruct(nullptr)
{
}
PropertyIntegerConstraint::~PropertyIntegerConstraint()
{
if (_ConstStruct && _ConstStruct->isDeletable())
delete _ConstStruct;
}
void PropertyIntegerConstraint::setConstraints(const Constraints* sConstrain)
{
if (_ConstStruct != sConstrain) {
if (_ConstStruct && _ConstStruct->isDeletable())
delete _ConstStruct;
}
_ConstStruct = sConstrain;
}
const PropertyIntegerConstraint::Constraints* PropertyIntegerConstraint::getConstraints() const
{
return _ConstStruct;
}
long PropertyIntegerConstraint::getMinimum() const
{
if (_ConstStruct)
return _ConstStruct->LowerBound;
// return the min of int, not long
return std::numeric_limits<int>::min();
}
long PropertyIntegerConstraint::getMaximum() const
{
if (_ConstStruct)
return _ConstStruct->UpperBound;
// return the max of int, not long
return std::numeric_limits<int>::max();
}
long PropertyIntegerConstraint::getStepSize() const
{
if (_ConstStruct)
return _ConstStruct->StepSize;
return 1;
}
void PropertyIntegerConstraint::setPyObject(PyObject *value)
{
if (PyLong_Check(value)) {
long temp = PyLong_AsLong(value);
if (_ConstStruct) {
if (temp > _ConstStruct->UpperBound)
temp = _ConstStruct->UpperBound;
else if(temp < _ConstStruct->LowerBound)
temp = _ConstStruct->LowerBound;
}
aboutToSetValue();
_lValue = temp;
hasSetValue();
}
else if (PyTuple_Check(value) && PyTuple_Size(value) == 4) {
long values[4];
for (int i=0; i<4; i++) {
PyObject* item;
item = PyTuple_GetItem(value,i);
if (PyLong_Check(item))
values[i] = PyLong_AsLong(item);
else
throw Base::TypeError("Type in tuple must be int");
}
Constraints* c = new Constraints();
c->setDeletable(true);
c->LowerBound = values[1];
c->UpperBound = values[2];
c->StepSize = std::max<long>(1, values[3]);
if (values[0] > c->UpperBound)
values[0] = c->UpperBound;
else if (values[0] < c->LowerBound)
values[0] = c->LowerBound;
setConstraints(c);
aboutToSetValue();
_lValue = values[0];
hasSetValue();
}
else {
std::string error = std::string("type must be int, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
//**************************************************************************
//**************************************************************************
// PropertyPercent
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyPercent , App::PropertyIntegerConstraint)
const PropertyIntegerConstraint::Constraints percent = {0,100,1};
//**************************************************************************
// Construction/Destruction
PropertyPercent::PropertyPercent()
{
_ConstStruct = &percent;
}
PropertyPercent::~PropertyPercent()
{
}
//**************************************************************************
//**************************************************************************
// PropertyIntegerList
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyIntegerList , App::PropertyLists)
//**************************************************************************
// Construction/Destruction
PropertyIntegerList::PropertyIntegerList()
{
}
PropertyIntegerList::~PropertyIntegerList()
{
}
//**************************************************************************
// Base class implementer
PyObject *PropertyIntegerList::getPyObject()
{
PyObject* list = PyList_New(getSize());
for(int i = 0;i<getSize(); i++)
PyList_SetItem( list, i, PyLong_FromLong(_lValueList[i]));
return list;
}
long PropertyIntegerList::getPyValue(PyObject *item) const {
if (PyLong_Check(item))
return PyLong_AsLong(item);
std::string error = std::string("type in list must be int, not ");
error += item->ob_type->tp_name;
throw Base::TypeError(error);
}
void PropertyIntegerList::Save (Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<IntegerList count=\"" << getSize() <<"\">" << endl;
writer.incInd();
for(int i = 0;i<getSize(); i++)
writer.Stream() << writer.ind() << "<I v=\"" << _lValueList[i] <<"\"/>" << endl; ;
writer.decInd();
writer.Stream() << writer.ind() << "</IntegerList>" << endl ;
}
void PropertyIntegerList::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("IntegerList");
// get the value of my Attribute
int count = reader.getAttributeAsInteger("count");
std::vector<long> values(count);
for(int i = 0; i < count; i++) {
reader.readElement("I");
values[i] = reader.getAttributeAsInteger("v");
}
reader.readEndElement("IntegerList");
//assignment
setValues(values);
}
Property *PropertyIntegerList::Copy() const
{
PropertyIntegerList *p= new PropertyIntegerList();
p->_lValueList = _lValueList;
return p;
}
void PropertyIntegerList::Paste(const Property &from)
{
setValues(dynamic_cast<const PropertyIntegerList&>(from)._lValueList);
}
unsigned int PropertyIntegerList::getMemSize () const
{
return static_cast<unsigned int>(_lValueList.size() * sizeof(long));
}
//**************************************************************************
//**************************************************************************
// PropertyIntegerSet
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyIntegerSet , App::Property)
//**************************************************************************
// Construction/Destruction
PropertyIntegerSet::PropertyIntegerSet()
{
}
PropertyIntegerSet::~PropertyIntegerSet()
{
}
//**************************************************************************
// Base class implementer
void PropertyIntegerSet::setValue(long lValue)
{
aboutToSetValue();
_lValueSet.clear();
_lValueSet.insert(lValue);
hasSetValue();
}
void PropertyIntegerSet::setValues(const std::set<long>& values)
{
aboutToSetValue();
_lValueSet = values;
hasSetValue();
}
PyObject *PropertyIntegerSet::getPyObject()
{
PyObject* set = PySet_New(nullptr);
for(std::set<long>::const_iterator it=_lValueSet.begin();it!=_lValueSet.end();++it)
PySet_Add(set,PyLong_FromLong(*it));
return set;
}
void PropertyIntegerSet::setPyObject(PyObject *value)
{
if (PySequence_Check(value)) {
Py_ssize_t nSize = PySequence_Length(value);
std::set<long> values;
for (Py_ssize_t i=0; i<nSize;++i) {
PyObject* item = PySequence_GetItem(value, i);
if (!PyLong_Check(item)) {
std::string error = std::string("type in list must be int, not ");
error += item->ob_type->tp_name;
throw Base::TypeError(error);
}
values.insert(PyLong_AsLong(item));
}
setValues(values);
}
else if (PyLong_Check(value)) {
setValue(PyLong_AsLong(value));
}
else {
std::string error = std::string("type must be int or list of int, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyIntegerSet::Save (Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<IntegerSet count=\"" << _lValueSet.size() <<"\">" << endl;
writer.incInd();
for(std::set<long>::const_iterator it=_lValueSet.begin();it!=_lValueSet.end();++it)
writer.Stream() << writer.ind() << "<I v=\"" << *it <<"\"/>" << endl; ;
writer.decInd();
writer.Stream() << writer.ind() << "</IntegerSet>" << endl ;
}
void PropertyIntegerSet::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("IntegerSet");
// get the value of my Attribute
int count = reader.getAttributeAsInteger("count");
std::set<long> values;
for(int i = 0; i < count; i++) {
reader.readElement("I");
values.insert(reader.getAttributeAsInteger("v"));
}
reader.readEndElement("IntegerSet");
//assignment
setValues(values);
}
Property *PropertyIntegerSet::Copy() const
{
PropertyIntegerSet *p= new PropertyIntegerSet();
p->_lValueSet = _lValueSet;
return p;
}
void PropertyIntegerSet::Paste(const Property &from)
{
aboutToSetValue();
_lValueSet = dynamic_cast<const PropertyIntegerSet&>(from)._lValueSet;
hasSetValue();
}
unsigned int PropertyIntegerSet::getMemSize () const
{
return static_cast<unsigned int>(_lValueSet.size() * sizeof(long));
}
//**************************************************************************
//**************************************************************************
// PropertyFloat
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyFloat , App::Property)
//**************************************************************************
// Construction/Destruction
PropertyFloat::PropertyFloat()
{
_dValue = 0.0;
}
PropertyFloat::~PropertyFloat()
{
}
//**************************************************************************
// Base class implementer
void PropertyFloat::setValue(double lValue)
{
aboutToSetValue();
_dValue=lValue;
hasSetValue();
}
double PropertyFloat::getValue() const
{
return _dValue;
}
PyObject *PropertyFloat::getPyObject()
{
return Py_BuildValue("d", _dValue);
}
void PropertyFloat::setPyObject(PyObject *value)
{
if (PyFloat_Check(value)) {
aboutToSetValue();
_dValue = PyFloat_AsDouble(value);
hasSetValue();
}
else if(PyLong_Check(value)) {
aboutToSetValue();
_dValue = PyLong_AsLong(value);
hasSetValue();
}
else {
std::string error = std::string("type must be float or int, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyFloat::Save (Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<Float value=\"" << _dValue <<"\"/>" << std::endl;
}
void PropertyFloat::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("Float");
// get the value of my Attribute
setValue(reader.getAttributeAsFloat("value"));
}
Property *PropertyFloat::Copy() const
{
PropertyFloat *p= new PropertyFloat();
p->_dValue = _dValue;
return p;
}
void PropertyFloat::Paste(const Property &from)
{
aboutToSetValue();
_dValue = dynamic_cast<const PropertyFloat&>(from)._dValue;
hasSetValue();
}
void PropertyFloat::setPathValue(const ObjectIdentifier &path, const boost::any &value)
{
verifyPath(path);
if (value.type() == typeid(long))
setValue(boost::any_cast<long>(value));
else if (value.type() == typeid(unsigned long))
setValue(boost::any_cast<unsigned long>(value));
else if (value.type() == typeid(int))
setValue(boost::any_cast<int>(value));
else if (value.type() == typeid(double))
setValue(boost::any_cast<double>(value));
else if (value.type() == typeid(float))
setValue(boost::any_cast<float>(value));
else if (value.type() == typeid(Quantity))
setValue((boost::any_cast<Quantity>(value)).getValue());
else
throw bad_cast();
}
const boost::any PropertyFloat::getPathValue(const ObjectIdentifier &path) const
{
verifyPath(path);
return _dValue;
}
//**************************************************************************
//**************************************************************************
// PropertyFloatConstraint
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyFloatConstraint, App::PropertyFloat)
//**************************************************************************
// Construction/Destruction
PropertyFloatConstraint::PropertyFloatConstraint()
: _ConstStruct(nullptr)
{
}
PropertyFloatConstraint::~PropertyFloatConstraint()
{
if (_ConstStruct && _ConstStruct->isDeletable())
delete _ConstStruct;
}
void PropertyFloatConstraint::setConstraints(const Constraints* sConstrain)
{
if (_ConstStruct != sConstrain) {
if (_ConstStruct && _ConstStruct->isDeletable())
delete _ConstStruct;
}
_ConstStruct = sConstrain;
}
const PropertyFloatConstraint::Constraints* PropertyFloatConstraint::getConstraints() const
{
return _ConstStruct;
}
double PropertyFloatConstraint::getMinimum() const
{
if (_ConstStruct)
return _ConstStruct->LowerBound;
return std::numeric_limits<double>::min();
}
double PropertyFloatConstraint::getMaximum() const
{
if (_ConstStruct)
return _ConstStruct->UpperBound;
return std::numeric_limits<double>::max();
}
double PropertyFloatConstraint::getStepSize() const
{
if (_ConstStruct)
return _ConstStruct->StepSize;
return 1.0;
}
void PropertyFloatConstraint::setPyObject(PyObject *value)
{
if (PyFloat_Check(value)) {
double temp = PyFloat_AsDouble(value);
if (_ConstStruct) {
if (temp > _ConstStruct->UpperBound)
temp = _ConstStruct->UpperBound;
else if (temp < _ConstStruct->LowerBound)
temp = _ConstStruct->LowerBound;
}
aboutToSetValue();
_dValue = temp;
hasSetValue();
}
else if (PyLong_Check(value)) {
double temp = (double)PyLong_AsLong(value);
if (_ConstStruct) {
if (temp > _ConstStruct->UpperBound)
temp = _ConstStruct->UpperBound;
else if (temp < _ConstStruct->LowerBound)
temp = _ConstStruct->LowerBound;
}
aboutToSetValue();
_dValue = temp;
hasSetValue();
}
else if (PyTuple_Check(value) && PyTuple_Size(value) == 4) {
double values[4];
for (int i=0; i<4; i++) {
PyObject* item;
item = PyTuple_GetItem(value,i);
if (PyFloat_Check(item))
values[i] = PyFloat_AsDouble(item);
else if (PyLong_Check(item))
values[i] = PyLong_AsLong(item);
else
throw Base::TypeError("Type in tuple must be float or int");
}
double stepSize = values[3];
// need a value > 0
if (stepSize < DBL_EPSILON)
throw Base::ValueError("Step size must be greater than zero");
Constraints* c = new Constraints();
c->setDeletable(true);
c->LowerBound = values[1];
c->UpperBound = values[2];
c->StepSize = stepSize;
if (values[0] > c->UpperBound)
values[0] = c->UpperBound;
else if (values[0] < c->LowerBound)
values[0] = c->LowerBound;
setConstraints(c);
aboutToSetValue();
_dValue = values[0];
hasSetValue();
}
else {
std::string error = std::string("type must be float, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
//**************************************************************************
// PropertyPrecision
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyPrecision, App::PropertyFloatConstraint)
//**************************************************************************
// Construction/Destruction
//
const PropertyFloatConstraint::Constraints PrecisionStandard = {0.0,DBL_MAX,0.001};
PropertyPrecision::PropertyPrecision()
{
setConstraints(&PrecisionStandard);
}
PropertyPrecision::~PropertyPrecision()
{
}
//**************************************************************************
// PropertyFloatList
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyFloatList , App::PropertyLists)
//**************************************************************************
// Construction/Destruction
PropertyFloatList::PropertyFloatList()
{
}
PropertyFloatList::~PropertyFloatList()
{
}
//**************************************************************************
// Base class implementer
PyObject *PropertyFloatList::getPyObject()
{
PyObject* list = PyList_New(getSize());
for (int i = 0;i<getSize(); i++)
PyList_SetItem( list, i, PyFloat_FromDouble(_lValueList[i]));
return list;
}
double PropertyFloatList::getPyValue(PyObject *item) const {
if (PyFloat_Check(item)) {
return PyFloat_AsDouble(item);
} else if (PyLong_Check(item)) {
return static_cast<double>(PyLong_AsLong(item));
} else {
std::string error = std::string("type in list must be float, not ");
error += item->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyFloatList::Save (Base::Writer &writer) const
{
if (writer.isForceXML()) {
writer.Stream() << writer.ind() << "<FloatList count=\"" << getSize() <<"\">" << endl;
writer.incInd();
for(int i = 0;i<getSize(); i++)
writer.Stream() << writer.ind() << "<F v=\"" << _lValueList[i] <<"\"/>" << endl; ;
writer.decInd();
writer.Stream() << writer.ind() <<"</FloatList>" << endl ;
}
else {
writer.Stream() << writer.ind() << "<FloatList file=\"" <<
(getSize()?writer.addFile(getName(), this):"") << "\"/>" << std::endl;
}
}
void PropertyFloatList::Restore(Base::XMLReader &reader)
{
reader.readElement("FloatList");
string file (reader.getAttribute("file") );
if (!file.empty()) {
// initiate a file read
reader.addFile(file.c_str(),this);
}
}
void PropertyFloatList::SaveDocFile (Base::Writer &writer) const
{
Base::OutputStream str(writer.Stream());
uint32_t uCt = (uint32_t)getSize();
str << uCt;
if (!isSinglePrecision()) {
for (std::vector<double>::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
str << *it;
}
}
else {
for (std::vector<double>::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
float v = (float)*it;
str << v;
}
}
}
void PropertyFloatList::RestoreDocFile(Base::Reader &reader)
{
Base::InputStream str(reader);
uint32_t uCt=0;
str >> uCt;
std::vector<double> values(uCt);
if (!isSinglePrecision()) {
for (std::vector<double>::iterator it = values.begin(); it != values.end(); ++it) {
str >> *it;
}
}
else {
for (std::vector<double>::iterator it = values.begin(); it != values.end(); ++it) {
float val;
str >> val;
(*it) = val;
}
}
setValues(values);
}
Property *PropertyFloatList::Copy() const
{
PropertyFloatList *p= new PropertyFloatList();
p->_lValueList = _lValueList;
return p;
}
void PropertyFloatList::Paste(const Property &from)
{
setValues(dynamic_cast<const PropertyFloatList&>(from)._lValueList);
}
unsigned int PropertyFloatList::getMemSize () const
{
return static_cast<unsigned int>(_lValueList.size() * sizeof(double));
}
//**************************************************************************
//**************************************************************************
// PropertyString
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyString , App::Property)
PropertyString::PropertyString()
{
}
PropertyString::~PropertyString()
{
}
void PropertyString::setValue(const char* newLabel)
{
if(!newLabel) return;
if(_cValue == newLabel)
return;
std::string _newLabel;
std::vector<std::pair<Property*,std::unique_ptr<Property> > > propChanges;
std::string label;
auto obj = dynamic_cast<DocumentObject*>(getContainer());
bool commit = false;
if(obj && obj->getNameInDocument() && this==&obj->Label &&
(!obj->getDocument()->testStatus(App::Document::Restoring)||
obj->getDocument()->testStatus(App::Document::Importing)) &&
!obj->getDocument()->isPerformingTransaction())
{
// allow object to control label change
static ParameterGrp::handle _hPGrp;
if(!_hPGrp) {
_hPGrp = GetApplication().GetUserParameter().GetGroup("BaseApp");
_hPGrp = _hPGrp->GetGroup("Preferences")->GetGroup("Document");
}
App::Document* doc = obj->getDocument();
if(doc && !_hPGrp->GetBool("DuplicateLabels") && !obj->allowDuplicateLabel()) {
std::vector<std::string> objectLabels;
std::vector<App::DocumentObject*>::const_iterator it;
std::vector<App::DocumentObject*> objs = doc->getObjects();
bool match = false;
for (it = objs.begin();it != objs.end();++it) {
if (*it == obj)
continue; // don't compare object with itself
std::string objLabel = (*it)->Label.getValue();
if (!match && objLabel == newLabel)
match = true;
objectLabels.push_back(objLabel);
}
// make sure that there is a name conflict otherwise we don't have to do anything
if (match && *newLabel) {
label = newLabel;
// remove number from end to avoid lengthy names
size_t lastpos = label.length()-1;
while (label[lastpos] >= 48 && label[lastpos] <= 57) {
// if 'lastpos' becomes 0 then all characters are digits. In this case we use
// the complete label again
if (lastpos == 0) {
lastpos = label.length()-1;
break;
}
lastpos--;
}
bool changed = false;
label = label.substr(0,lastpos+1);
if(label != obj->getNameInDocument()
&& boost::starts_with(obj->getNameInDocument(),label))
{
// In case the label has the same base name as object's
// internal name, use it as the label instead.
const char *objName = obj->getNameInDocument();
const char *c = &objName[lastpos+1];
for(;*c;++c) {
if(*c<48 || *c>57)
break;
}
if(*c == 0 && std::find(objectLabels.begin(), objectLabels.end(),
obj->getNameInDocument())==objectLabels.end())
{
label = obj->getNameInDocument();
changed = true;
}
}
if(!changed)
label = Base::Tools::getUniqueName(label, objectLabels, 3);
}
}
if(label.empty())
label = newLabel;
obj->onBeforeChangeLabel(label);
newLabel = label.c_str();
if(!obj->getDocument()->testStatus(App::Document::Restoring)) {
// Only update label reference if we are not restoring. When
// importing (which also counts as restoring), it is possible the
// new object changes its label. However, we cannot update label
// references here, because object restoring is not based on
// dependency order. It can only be done in afterRestore().
//
// See PropertyLinkBase::restoreLabelReference() for more details.
propChanges = PropertyLinkBase::updateLabelReferences(obj,newLabel);
}
if(propChanges.size() && !GetApplication().getActiveTransaction()) {
commit = true;
std::ostringstream str;
str << "Change " << obj->getNameInDocument() << ".Label";
GetApplication().setActiveTransaction(str.str().c_str());
}
}
aboutToSetValue();
_cValue = newLabel;
hasSetValue();
for(auto &change : propChanges)
change.first->Paste(*change.second.get());
if(commit)
GetApplication().closeActiveTransaction();
}
void PropertyString::setValue(const std::string &sString)
{
setValue(sString.c_str());
}
const char* PropertyString::getValue() const
{
return _cValue.c_str();
}
PyObject *PropertyString::getPyObject()
{
PyObject *p = PyUnicode_DecodeUTF8(_cValue.c_str(),_cValue.size(),nullptr);
if (!p) throw Base::UnicodeError("UTF8 conversion failure at PropertyString::getPyObject()");
return p;
}
void PropertyString::setPyObject(PyObject *value)
{
std::string string;
if (PyUnicode_Check(value)) {
string = PyUnicode_AsUTF8(value);
}
else {
std::string error = std::string("type must be str or unicode, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
// assign the string
setValue(string);
}
void PropertyString::Save (Base::Writer &writer) const
{
std::string val;
auto obj = dynamic_cast<DocumentObject*>(getContainer());
writer.Stream() << writer.ind() << "<String ";
bool exported = false;
if(obj && obj->getNameInDocument() &&
obj->isExporting() && &obj->Label==this)
{
if(obj->allowDuplicateLabel())
writer.Stream() <<"restore=\"1\" ";
else if(_cValue==obj->getNameInDocument()) {
writer.Stream() <<"restore=\"0\" ";
val = encodeAttribute(obj->getExportName());
exported = true;
}
}
if(!exported)
val = encodeAttribute(_cValue);
writer.Stream() <<"value=\"" << val <<"\"/>" << std::endl;
}
void PropertyString::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("String");
// get the value of my Attribute
auto obj = dynamic_cast<DocumentObject*>(getContainer());
if(obj && &obj->Label==this) {
if(reader.hasAttribute("restore")) {
int restore = reader.getAttributeAsInteger("restore");
if(restore == 1) {
aboutToSetValue();
_cValue = reader.getAttribute("value");
hasSetValue();
}else
setValue(reader.getName(reader.getAttribute("value")));
} else
setValue(reader.getAttribute("value"));
}else
setValue(reader.getAttribute("value"));
}
Property *PropertyString::Copy() const
{
PropertyString *p= new PropertyString();
p->_cValue = _cValue;
return p;
}
void PropertyString::Paste(const Property &from)
{
setValue(dynamic_cast<const PropertyString&>(from)._cValue);
}
unsigned int PropertyString::getMemSize () const
{
return static_cast<unsigned int>(_cValue.size());
}
void PropertyString::setPathValue(const ObjectIdentifier &path, const boost::any &value)
{
verifyPath(path);
if (value.type() == typeid(bool))
setValue(boost::any_cast<bool>(value)?"True":"False");
else if (value.type() == typeid(int))
setValue(std::to_string(boost::any_cast<int>(value)));
else if (value.type() == typeid(long))
setValue(std::to_string(boost::any_cast<long>(value)));
else if (value.type() == typeid(double))
setValue(std::to_string(App::any_cast<double>(value)));
else if (value.type() == typeid(float))
setValue(std::to_string(App::any_cast<float>(value)));
else if (value.type() == typeid(Quantity))
setValue(boost::any_cast<Quantity>(value).getUserString().toUtf8().constData());
else if (value.type() == typeid(std::string))
setValue(boost::any_cast<const std::string &>(value));
else {
Base::PyGILStateLocker lock;
setValue(pyObjectFromAny(value).as_string());
}
}
const boost::any PropertyString::getPathValue(const ObjectIdentifier &path) const
{
verifyPath(path);
return _cValue;
}
//**************************************************************************
//**************************************************************************
// PropertyUUID
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyUUID , App::Property)
PropertyUUID::PropertyUUID()
{
}
PropertyUUID::~PropertyUUID()
{
}
void PropertyUUID::setValue(const Base::Uuid &id)
{
aboutToSetValue();
_uuid = id;
hasSetValue();
}
void PropertyUUID::setValue(const char* sString)
{
if (sString) {
aboutToSetValue();
_uuid.setValue(sString);
hasSetValue();
}
}
void PropertyUUID::setValue(const std::string &sString)
{
aboutToSetValue();
_uuid.setValue(sString);
hasSetValue();
}
const std::string& PropertyUUID::getValueStr() const
{
return _uuid.getValue();
}
const Base::Uuid& PropertyUUID::getValue() const
{
return _uuid;
}
PyObject *PropertyUUID::getPyObject()
{
PyObject *p = PyUnicode_FromString(_uuid.getValue().c_str());
return p;
}
void PropertyUUID::setPyObject(PyObject *value)
{
std::string string;
if (PyUnicode_Check(value)) {
string = PyUnicode_AsUTF8(value);
}
else {
std::string error = std::string("type must be unicode or str, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
try {
// assign the string
Base::Uuid uid;
uid.setValue(string);
setValue(uid);
}
catch (const std::exception& e) {
throw Base::RuntimeError(e.what());
}
}
void PropertyUUID::Save (Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<Uuid value=\"" << _uuid.getValue() <<"\"/>" << std::endl;
}
void PropertyUUID::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("Uuid");
// get the value of my Attribute
setValue(reader.getAttribute("value"));
}
Property *PropertyUUID::Copy() const
{
PropertyUUID *p= new PropertyUUID();
p->_uuid = _uuid;
return p;
}
void PropertyUUID::Paste(const Property &from)
{
aboutToSetValue();
_uuid = dynamic_cast<const PropertyUUID&>(from)._uuid;
hasSetValue();
}
unsigned int PropertyUUID::getMemSize () const
{
return static_cast<unsigned int>(sizeof(_uuid));
}
//**************************************************************************
// PropertyFont
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyFont , App::PropertyString)
PropertyFont::PropertyFont()
{
}
PropertyFont::~PropertyFont()
{
}
//**************************************************************************
// PropertyStringList
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyStringList , App::PropertyLists)
PropertyStringList::PropertyStringList()
{
}
PropertyStringList::~PropertyStringList()
{
}
//**************************************************************************
// Base class implementer
void PropertyStringList::setValues(const std::list<std::string>& lValue)
{
std::vector<std::string> vals;
vals.reserve(lValue.size());
for(const auto &v : lValue)
vals.push_back(v);
setValues(vals);
}
PyObject *PropertyStringList::getPyObject()
{
PyObject* list = PyList_New(getSize());
for (int i = 0;i<getSize(); i++) {
PyObject* item = PyUnicode_DecodeUTF8(_lValueList[i].c_str(), _lValueList[i].size(), nullptr);
if (!item) {
Py_DECREF(list);
throw Base::UnicodeError("UTF8 conversion failure at PropertyStringList::getPyObject()");
}
PyList_SetItem(list, i, item);
}
return list;
}
std::string PropertyStringList::getPyValue(PyObject *item) const
{
std::string ret;
if (PyUnicode_Check(item)) {
ret = PyUnicode_AsUTF8(item);
} else if (PyBytes_Check(item)) {
ret = PyBytes_AsString(item);
} else {
std::string error = std::string("type in list must be str or unicode, not ");
error += item->ob_type->tp_name;
throw Base::TypeError(error);
}
return ret;
}
unsigned int PropertyStringList::getMemSize () const
{
size_t size=0;
for(int i = 0;i<getSize(); i++)
size += _lValueList[i].size();
return static_cast<unsigned int>(size);
}
void PropertyStringList::Save (Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<StringList count=\"" << getSize() <<"\">" << endl;
writer.incInd();
for(int i = 0;i<getSize(); i++) {
std::string val = encodeAttribute(_lValueList[i]);
writer.Stream() << writer.ind() << "<String value=\"" << val <<"\"/>" << endl;
}
writer.decInd();
writer.Stream() << writer.ind() << "</StringList>" << endl ;
}
void PropertyStringList::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("StringList");
// get the value of my Attribute
int count = reader.getAttributeAsInteger("count");
std::vector<std::string> values(count);
for(int i = 0; i < count; i++) {
reader.readElement("String");
values[i] = reader.getAttribute("value");
}
reader.readEndElement("StringList");
// assignment
setValues(values);
}
Property *PropertyStringList::Copy() const
{
PropertyStringList *p= new PropertyStringList();
p->_lValueList = _lValueList;
return p;
}
void PropertyStringList::Paste(const Property &from)
{
setValues(dynamic_cast<const PropertyStringList&>(from)._lValueList);
}
//**************************************************************************
// PropertyMap
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyMap , App::Property)
PropertyMap::PropertyMap()
{
}
PropertyMap::~PropertyMap()
{
}
//**************************************************************************
// Base class implementer
int PropertyMap::getSize() const
{
return static_cast<int>(_lValueList.size());
}
void PropertyMap::setValue(const std::string& key,const std::string& value)
{
aboutToSetValue();
_lValueList[key] = value;
hasSetValue();
}
void PropertyMap::setValues(const std::map<std::string,std::string>& map)
{
aboutToSetValue();
_lValueList=map;
hasSetValue();
}
const std::string& PropertyMap::operator[] (const std::string& key) const
{
static std::string empty;
std::map<std::string,std::string>::const_iterator it = _lValueList.find(key);
if(it!=_lValueList.end())
return it->second;
else
return empty;
}
PyObject *PropertyMap::getPyObject()
{
PyObject* dict = PyDict_New();
for (std::map<std::string,std::string>::const_iterator it = _lValueList.begin();it!= _lValueList.end(); ++it) {
PyObject* item = PyUnicode_DecodeUTF8(it->second.c_str(), it->second.size(), nullptr);
if (!item) {
Py_DECREF(dict);
throw Base::UnicodeError("UTF8 conversion failure at PropertyMap::getPyObject()");
}
PyDict_SetItemString(dict,it->first.c_str(),item);
Py_DECREF(item);
}
return dict;
}
void PropertyMap::setPyObject(PyObject *value)
{
if (PyDict_Check(value)) {
std::map<std::string,std::string> values;
// get key and item list
PyObject* keyList = PyDict_Keys(value);
PyObject* itemList = PyDict_Values(value);
Py_ssize_t nSize = PyList_Size(keyList);
for (Py_ssize_t i=0; i<nSize;++i) {
// check on the key:
std::string keyStr;
PyObject* key = PyList_GetItem(keyList, i);
if (PyUnicode_Check(key)) {
keyStr = PyUnicode_AsUTF8(key);
}
else {
std::string error = std::string("type of the key need to be unicode or string, not");
error += key->ob_type->tp_name;
throw Base::TypeError(error);
}
// check on the item:
PyObject* item = PyList_GetItem(itemList, i);
if (PyUnicode_Check(item)) {
values[keyStr] = PyUnicode_AsUTF8(item);
}
else {
std::string error = std::string("type in list must be string or unicode, not ");
error += item->ob_type->tp_name;
throw Base::TypeError(error);
}
}
setValues(values);
}
else {
std::string error = std::string("type must be a dict object");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
unsigned int PropertyMap::getMemSize () const
{
size_t size=0;
for (std::map<std::string,std::string>::const_iterator it = _lValueList.begin();it!= _lValueList.end(); ++it) {
size += it->second.size();
size += it->first.size();
}
return size;
}
void PropertyMap::Save (Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<Map count=\"" << getSize() <<"\">" << endl;
writer.incInd();
for (std::map<std::string,std::string>::const_iterator it = _lValueList.begin();it!= _lValueList.end(); ++it) {
writer.Stream() << writer.ind() << "<Item key=\"" << encodeAttribute(it->first)
<< "\" value=\"" << encodeAttribute(it->second) <<"\"/>" << endl;
}
writer.decInd();
writer.Stream() << writer.ind() << "</Map>" << endl ;
}
void PropertyMap::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("Map");
// get the value of my Attribute
int count = reader.getAttributeAsInteger("count");
std::map<std::string,std::string> values;
for(int i = 0; i < count; i++) {
reader.readElement("Item");
values[reader.getAttribute("key")] = reader.getAttribute("value");
}
reader.readEndElement("Map");
// assignment
setValues(values);
}
Property *PropertyMap::Copy() const
{
PropertyMap *p= new PropertyMap();
p->_lValueList = _lValueList;
return p;
}
void PropertyMap::Paste(const Property &from)
{
aboutToSetValue();
_lValueList = dynamic_cast<const PropertyMap&>(from)._lValueList;
hasSetValue();
}
//**************************************************************************
//**************************************************************************
// PropertyBool
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyBool , App::Property)
//**************************************************************************
// Construction/Destruction
PropertyBool::PropertyBool()
{
_lValue = false;
}
PropertyBool::~PropertyBool()
{
}
//**************************************************************************
// Setter/getter for the property
void PropertyBool::setValue(bool lValue)
{
aboutToSetValue();
_lValue=lValue;
hasSetValue();
}
bool PropertyBool::getValue() const
{
return _lValue;
}
PyObject *PropertyBool::getPyObject()
{
return PyBool_FromLong(_lValue ? 1 : 0);
}
void PropertyBool::setPyObject(PyObject *value)
{
if (PyBool_Check(value))
setValue(PyObject_IsTrue(value)!=0);
else if(PyLong_Check(value))
setValue(PyLong_AsLong(value)!=0);
else {
std::string error = std::string("type must be bool, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyBool::Save (Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<Bool value=\"" ;
if (_lValue)
writer.Stream() << "true" <<"\"/>" ;
else
writer.Stream() << "false" <<"\"/>" ;
writer.Stream() << std::endl;
}
void PropertyBool::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("Bool");
// get the value of my Attribute
string b = reader.getAttribute("value");
(b == "true") ? setValue(true) : setValue(false);
}
Property *PropertyBool::Copy() const
{
PropertyBool *p= new PropertyBool();
p->_lValue = _lValue;
return p;
}
void PropertyBool::Paste(const Property &from)
{
aboutToSetValue();
_lValue = dynamic_cast<const PropertyBool&>(from)._lValue;
hasSetValue();
}
void PropertyBool::setPathValue(const ObjectIdentifier &path, const boost::any &value)
{
verifyPath(path);
if (value.type() == typeid(bool))
setValue(boost::any_cast<bool>(value));
else if (value.type() == typeid(int))
setValue(boost::any_cast<int>(value) != 0);
else if (value.type() == typeid(long))
setValue(boost::any_cast<long>(value) != 0);
else if (value.type() == typeid(double))
setValue(boost::math::round(boost::any_cast<double>(value)));
else if (value.type() == typeid(float))
setValue(boost::math::round(boost::any_cast<float>(value)));
else if (value.type() == typeid(Quantity))
setValue(boost::any_cast<Quantity>(value).getValue() != 0);
else
throw bad_cast();
}
const boost::any PropertyBool::getPathValue(const ObjectIdentifier &path) const
{
verifyPath(path);
return _lValue;
}
//**************************************************************************
//**************************************************************************
// PropertyBoolList
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyBoolList , App::PropertyLists)
//**************************************************************************
// Construction/Destruction
PropertyBoolList::PropertyBoolList()
{
}
PropertyBoolList::~PropertyBoolList()
{
}
//**************************************************************************
// Base class implementer
PyObject *PropertyBoolList::getPyObject()
{
PyObject* tuple = PyTuple_New(getSize());
for(int i = 0;i<getSize(); i++) {
bool v = _lValueList[i];
if (v) {
PyTuple_SetItem(tuple, i, PyBool_FromLong(1));
}
else {
PyTuple_SetItem(tuple, i, PyBool_FromLong(0));
}
}
return tuple;
}
void PropertyBoolList::setPyObject(PyObject *value)
{
// string is also a sequence and must be treated differently
std::string str;
if (PyUnicode_Check(value)) {
str = PyUnicode_AsUTF8(value);
boost::dynamic_bitset<> values(str);
setValues(values);
}else
inherited::setPyObject(value);
}
bool PropertyBoolList::getPyValue(PyObject *item) const {
if (PyBool_Check(item)) {
return (PyObject_IsTrue(item) ? true : false);
} else if (PyLong_Check(item)) {
return (PyLong_AsLong(item) ? true : false);
} else {
std::string error = std::string("type in list must be bool or int, not ");
error += item->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyBoolList::Save (Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<BoolList value=\"" ;
std::string bitset;
boost::to_string(_lValueList, bitset);
writer.Stream() << bitset <<"\"/>" ;
writer.Stream() << std::endl;
}
void PropertyBoolList::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("BoolList");
// get the value of my Attribute
string str = reader.getAttribute("value");
boost::dynamic_bitset<> bitset(str);
setValues(bitset);
}
Property *PropertyBoolList::Copy() const
{
PropertyBoolList *p= new PropertyBoolList();
p->_lValueList = _lValueList;
return p;
}
void PropertyBoolList::Paste(const Property &from)
{
setValues(dynamic_cast<const PropertyBoolList&>(from)._lValueList);
}
unsigned int PropertyBoolList::getMemSize () const
{
return static_cast<unsigned int>(_lValueList.size());
}
//**************************************************************************
//**************************************************************************
// PropertyColor
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyColor , App::Property)
//**************************************************************************
// Construction/Destruction
PropertyColor::PropertyColor()
{
}
PropertyColor::~PropertyColor()
{
}
//**************************************************************************
// Base class implementer
void PropertyColor::setValue(const Color &col)
{
aboutToSetValue();
_cCol=col;
hasSetValue();
}
void PropertyColor::setValue(uint32_t rgba)
{
aboutToSetValue();
_cCol.setPackedValue(rgba);
hasSetValue();
}
void PropertyColor::setValue(float r, float g, float b, float a)
{
aboutToSetValue();
_cCol.set(r,g,b,a);
hasSetValue();
}
const Color& PropertyColor::getValue() const
{
return _cCol;
}
PyObject *PropertyColor::getPyObject()
{
PyObject* rgba = PyTuple_New(4);
PyObject* r = PyFloat_FromDouble(_cCol.r);
PyObject* g = PyFloat_FromDouble(_cCol.g);
PyObject* b = PyFloat_FromDouble(_cCol.b);
PyObject* a = PyFloat_FromDouble(_cCol.a);
PyTuple_SetItem(rgba, 0, r);
PyTuple_SetItem(rgba, 1, g);
PyTuple_SetItem(rgba, 2, b);
PyTuple_SetItem(rgba, 3, a);
return rgba;
}
void PropertyColor::setPyObject(PyObject *value)
{
App::Color cCol;
if (PyTuple_Check(value) && PyTuple_Size(value) == 3) {
PyObject* item;
item = PyTuple_GetItem(value,0);
if (PyFloat_Check(item))
cCol.r = (float)PyFloat_AsDouble(item);
else
throw Base::TypeError("Type in tuple must be float");
item = PyTuple_GetItem(value,1);
if (PyFloat_Check(item))
cCol.g = (float)PyFloat_AsDouble(item);
else
throw Base::TypeError("Type in tuple must be float");
item = PyTuple_GetItem(value,2);
if (PyFloat_Check(item))
cCol.b = (float)PyFloat_AsDouble(item);
else
throw Base::TypeError("Type in tuple must be float");
}
else if (PyTuple_Check(value) && PyTuple_Size(value) == 4) {
PyObject* item;
item = PyTuple_GetItem(value,0);
if (PyFloat_Check(item))
cCol.r = (float)PyFloat_AsDouble(item);
else
throw Base::TypeError("Type in tuple must be float");
item = PyTuple_GetItem(value,1);
if (PyFloat_Check(item))
cCol.g = (float)PyFloat_AsDouble(item);
else
throw Base::TypeError("Type in tuple must be float");
item = PyTuple_GetItem(value,2);
if (PyFloat_Check(item))
cCol.b = (float)PyFloat_AsDouble(item);
else
throw Base::TypeError("Type in tuple must be float");
item = PyTuple_GetItem(value,3);
if (PyFloat_Check(item))
cCol.a = (float)PyFloat_AsDouble(item);
else
throw Base::TypeError("Type in tuple must be float");
}
else if (PyLong_Check(value)) {
cCol.setPackedValue(PyLong_AsUnsignedLong(value));
}
else {
std::string error = std::string("type must be int or tuple of float, not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
setValue( cCol );
}
void PropertyColor::Save (Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<PropertyColor value=\""
<< _cCol.getPackedValue() <<"\"/>" << endl;
}
void PropertyColor::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("PropertyColor");
// get the value of my Attribute
unsigned long rgba = reader.getAttributeAsUnsigned("value");
setValue(rgba);
}
Property *PropertyColor::Copy() const
{
PropertyColor *p= new PropertyColor();
p->_cCol = _cCol;
return p;
}
void PropertyColor::Paste(const Property &from)
{
aboutToSetValue();
_cCol = dynamic_cast<const PropertyColor&>(from)._cCol;
hasSetValue();
}
//**************************************************************************
// PropertyColorList
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyColorList , App::PropertyLists)
//**************************************************************************
// Construction/Destruction
PropertyColorList::PropertyColorList()
{
}
PropertyColorList::~PropertyColorList()
{
}
//**************************************************************************
// Base class implementer
PyObject *PropertyColorList::getPyObject()
{
PyObject* list = PyList_New(getSize());
for(int i = 0;i<getSize(); i++) {
PyObject* rgba = PyTuple_New(4);
PyObject* r = PyFloat_FromDouble(_lValueList[i].r);
PyObject* g = PyFloat_FromDouble(_lValueList[i].g);
PyObject* b = PyFloat_FromDouble(_lValueList[i].b);
PyObject* a = PyFloat_FromDouble(_lValueList[i].a);
PyTuple_SetItem(rgba, 0, r);
PyTuple_SetItem(rgba, 1, g);
PyTuple_SetItem(rgba, 2, b);
PyTuple_SetItem(rgba, 3, a);
PyList_SetItem( list, i, rgba );
}
return list;
}
Color PropertyColorList::getPyValue(PyObject *item) const {
PropertyColor col;
col.setPyObject(item);
return col.getValue();
}
void PropertyColorList::Save (Base::Writer &writer) const
{
if (!writer.isForceXML()) {
writer.Stream() << writer.ind() << "<ColorList file=\"" <<
(getSize()?writer.addFile(getName(), this):"") << "\"/>" << std::endl;
}
}
void PropertyColorList::Restore(Base::XMLReader &reader)
{
reader.readElement("ColorList");
if (reader.hasAttribute("file")) {
std::string file (reader.getAttribute("file"));
if (!file.empty()) {
// initiate a file read
reader.addFile(file.c_str(),this);
}
}
}
void PropertyColorList::SaveDocFile (Base::Writer &writer) const
{
Base::OutputStream str(writer.Stream());
uint32_t uCt = (uint32_t)getSize();
str << uCt;
for (std::vector<App::Color>::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
str << it->getPackedValue();
}
}
void PropertyColorList::RestoreDocFile(Base::Reader &reader)
{
Base::InputStream str(reader);
uint32_t uCt=0;
str >> uCt;
std::vector<Color> values(uCt);
uint32_t value; // must be 32 bit long
for (std::vector<App::Color>::iterator it = values.begin(); it != values.end(); ++it) {
str >> value;
it->setPackedValue(value);
}
setValues(values);
}
Property *PropertyColorList::Copy() const
{
PropertyColorList *p= new PropertyColorList();
p->_lValueList = _lValueList;
return p;
}
void PropertyColorList::Paste(const Property &from)
{
setValues(dynamic_cast<const PropertyColorList&>(from)._lValueList);
}
unsigned int PropertyColorList::getMemSize () const
{
return static_cast<unsigned int>(_lValueList.size() * sizeof(Color));
}
//**************************************************************************
//**************************************************************************
// PropertyMaterial
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyMaterial , App::Property)
PropertyMaterial::PropertyMaterial()
{
}
PropertyMaterial::~PropertyMaterial()
{
}
void PropertyMaterial::setValue(const Material &mat)
{
aboutToSetValue();
_cMat=mat;
hasSetValue();
}
const Material& PropertyMaterial::getValue() const
{
return _cMat;
}
void PropertyMaterial::setAmbientColor(const Color& col)
{
aboutToSetValue();
_cMat.ambientColor = col;
hasSetValue();
}
void PropertyMaterial::setDiffuseColor(const Color& col)
{
aboutToSetValue();
_cMat.diffuseColor = col;
hasSetValue();
}
void PropertyMaterial::setSpecularColor(const Color& col)
{
aboutToSetValue();
_cMat.specularColor = col;
hasSetValue();
}
void PropertyMaterial::setEmissiveColor(const Color& col)
{
aboutToSetValue();
_cMat.emissiveColor = col;
hasSetValue();
}
void PropertyMaterial::setShininess(float val)
{
aboutToSetValue();
_cMat.shininess = val;
hasSetValue();
}
void PropertyMaterial::setTransparency(float val)
{
aboutToSetValue();
_cMat.transparency = val;
hasSetValue();
}
PyObject *PropertyMaterial::getPyObject()
{
return new MaterialPy(new Material(_cMat));
}
void PropertyMaterial::setPyObject(PyObject *value)
{
if (PyObject_TypeCheck(value, &(MaterialPy::Type))) {
setValue(*static_cast<MaterialPy*>(value)->getMaterialPtr());
}
else {
std::string error = std::string("type must be 'Material', not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyMaterial::Save (Base::Writer &writer) const
{
writer.Stream() << writer.ind() << "<PropertyMaterial ambientColor=\""
<< _cMat.ambientColor.getPackedValue()
<< "\" diffuseColor=\"" << _cMat.diffuseColor.getPackedValue()
<< "\" specularColor=\"" << _cMat.specularColor.getPackedValue()
<< "\" emissiveColor=\"" << _cMat.emissiveColor.getPackedValue()
<< "\" shininess=\"" << _cMat.shininess
<< "\" transparency=\"" << _cMat.transparency
<< "\"/>" << endl;
}
void PropertyMaterial::Restore(Base::XMLReader &reader)
{
// read my Element
reader.readElement("PropertyMaterial");
// get the value of my Attribute
aboutToSetValue();
_cMat.ambientColor.setPackedValue(reader.getAttributeAsUnsigned("ambientColor"));
_cMat.diffuseColor.setPackedValue(reader.getAttributeAsUnsigned("diffuseColor"));
_cMat.specularColor.setPackedValue(reader.getAttributeAsUnsigned("specularColor"));
_cMat.emissiveColor.setPackedValue(reader.getAttributeAsUnsigned("emissiveColor"));
_cMat.shininess = (float)reader.getAttributeAsFloat("shininess");
_cMat.transparency = (float)reader.getAttributeAsFloat("transparency");
hasSetValue();
}
const char* PropertyMaterial::getEditorName() const
{
if(testStatus(MaterialEdit))
return "Gui::PropertyEditor::PropertyMaterialItem";
return "";
}
Property *PropertyMaterial::Copy() const
{
PropertyMaterial *p= new PropertyMaterial();
p->_cMat = _cMat;
return p;
}
void PropertyMaterial::Paste(const Property &from)
{
aboutToSetValue();
_cMat = dynamic_cast<const PropertyMaterial&>(from)._cMat;
hasSetValue();
}
//**************************************************************************
// PropertyMaterialList
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyMaterialList, App::PropertyLists)
//**************************************************************************
// Construction/Destruction
PropertyMaterialList::PropertyMaterialList()
{
}
PropertyMaterialList::~PropertyMaterialList()
{
}
//**************************************************************************
// Base class implementer
PyObject *PropertyMaterialList::getPyObject()
{
Py::Tuple tuple(getSize());
for (int i = 0; i<getSize(); i++) {
tuple.setItem(i, Py::asObject(new MaterialPy(new Material(_lValueList[i]))));
}
return Py::new_reference_to(tuple);
}
Material PropertyMaterialList::getPyValue(PyObject *value) const {
if (PyObject_TypeCheck(value, &(MaterialPy::Type)))
return *static_cast<MaterialPy*>(value)->getMaterialPtr();
else {
std::string error = std::string("type must be 'Material', not ");
error += value->ob_type->tp_name;
throw Base::TypeError(error);
}
}
void PropertyMaterialList::Save(Base::Writer &writer) const
{
if (!writer.isForceXML()) {
writer.Stream() << writer.ind() << "<MaterialList file=\"" <<
(getSize()?writer.addFile(getName(), this):"") << "\"/>" << std::endl;
}
}
void PropertyMaterialList::Restore(Base::XMLReader &reader)
{
reader.readElement("MaterialList");
if (reader.hasAttribute("file")) {
std::string file(reader.getAttribute("file"));
if (!file.empty()) {
// initiate a file read
reader.addFile(file.c_str(), this);
}
}
}
void PropertyMaterialList::SaveDocFile(Base::Writer &writer) const
{
Base::OutputStream str(writer.Stream());
uint32_t uCt = (uint32_t)getSize();
str << uCt;
for (std::vector<App::Material>::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
str << it->ambientColor.getPackedValue();
str << it->diffuseColor.getPackedValue();
str << it->specularColor.getPackedValue();
str << it->emissiveColor.getPackedValue();
str << it->shininess;
str << it->transparency;
}
}
void PropertyMaterialList::RestoreDocFile(Base::Reader &reader)
{
Base::InputStream str(reader);
uint32_t uCt = 0;
str >> uCt;
std::vector<Material> values(uCt);
uint32_t value; // must be 32 bit long
float valueF;
for (std::vector<App::Material>::iterator it = values.begin(); it != values.end(); ++it) {
str >> value;
it->ambientColor.setPackedValue(value);
str >> value;
it->diffuseColor.setPackedValue(value);
str >> value;
it->specularColor.setPackedValue(value);
str >> value;
it->emissiveColor.setPackedValue(value);
str >> valueF;
it->shininess = valueF;
str >> valueF;
it->transparency = valueF;
}
setValues(values);
}
const char* PropertyMaterialList::getEditorName() const
{
if(testStatus(NoMaterialListEdit))
return "";
return "Gui::PropertyEditor::PropertyMaterialListItem";
}
Property *PropertyMaterialList::Copy() const
{
PropertyMaterialList *p = new PropertyMaterialList();
p->_lValueList = _lValueList;
return p;
}
void PropertyMaterialList::Paste(const Property &from)
{
setValues(dynamic_cast<const PropertyMaterialList&>(from)._lValueList);
}
unsigned int PropertyMaterialList::getMemSize() const
{
return static_cast<unsigned int>(_lValueList.size() * sizeof(Material));
}
//**************************************************************************
// PropertyPersistentObject
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
TYPESYSTEM_SOURCE(App::PropertyPersistentObject , App::PropertyString)
PyObject *PropertyPersistentObject::getPyObject(void){
if(_pObject)
return _pObject->getPyObject();
return inherited::getPyObject();
}
void PropertyPersistentObject::Save(Base::Writer &writer) const{
inherited::Save(writer);
#define ELEMENT_PERSISTENT_OBJ "PersistentObject"
writer.Stream() << writer.ind() << "<" ELEMENT_PERSISTENT_OBJ ">" << std::endl;
if(_pObject) {
writer.incInd();
_pObject->Save(writer);
writer.decInd();
}
writer.Stream() << writer.ind() << "</" ELEMENT_PERSISTENT_OBJ ">" << std::endl;
}
void PropertyPersistentObject::Restore(Base::XMLReader &reader){
inherited::Restore(reader);
reader.readElement(ELEMENT_PERSISTENT_OBJ);
if(_pObject)
_pObject->Restore(reader);
reader.readEndElement(ELEMENT_PERSISTENT_OBJ);
}
Property *PropertyPersistentObject::Copy(void) const{
auto *p= new PropertyPersistentObject();
p->_cValue = _cValue;
p->_pObject = _pObject;
return p;
}
void PropertyPersistentObject::Paste(const Property &from){
const auto &prop = dynamic_cast<const PropertyPersistentObject&>(from);
if(_cValue!=prop._cValue || _pObject!=prop._pObject) {
aboutToSetValue();
_cValue = prop._cValue;
_pObject = prop._pObject;
hasSetValue();
}
}
unsigned int PropertyPersistentObject::getMemSize () const{
auto size = inherited::getMemSize();
if(_pObject)
size += _pObject->getMemSize();
return size;
}
void PropertyPersistentObject::setValue(const char *type) {
if(!type) type = "";
if(type[0]) {
Base::Type::importModule(type);
Base::Type t = Base::Type::fromName(type);
if(t.isBad())
throw Base::TypeError("Invalid type");
if(!t.isDerivedFrom(Persistence::getClassTypeId()))
throw Base::TypeError("Type must be derived from Base::Persistence");
if(_pObject && _pObject->getTypeId()==t)
return;
}
aboutToSetValue();
_pObject.reset();
_cValue = type;
if(type[0])
_pObject.reset(static_cast<Base::Persistence*>(Base::Type::createInstanceByName(type)));
hasSetValue();
}