/**************************************************************************** * Copyright (c) 2017 Zheng Lei (realthunder) * * * * 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" #ifndef _PreComp_ # include #endif #include "DocumentObjectPy.h" #include "LinkBaseExtensionPy.h" #include "LinkBaseExtensionPy.cpp" using namespace App; // returns a string which represent the object e.g. when printed in python std::string LinkBaseExtensionPy::representation() const { std::ostringstream str; str << "<" << getLinkBaseExtensionPtr()->getExtensionClassTypeId().getName() << ">"; return str.str(); } using PropTmpMap = std::map >; using PropMap = std::map; static bool getProperty(PropTmpMap &props, const LinkBaseExtension::PropInfoMap &infoMap, const PropMap &propMap, PyObject *key, PyObject *value) { std::ostringstream str; if(!PyUnicode_Check(key)) { PyErr_SetString(PyExc_TypeError, "key must be a unicode string"); return false; } const char *keyStr = PyUnicode_AsUTF8(key); auto it = infoMap.find(keyStr); if(it == infoMap.end()){ str << "unknown key '" << keyStr << "'"; PyErr_SetString(PyExc_KeyError, str.str().c_str()); return false; } const char *valStr = nullptr; if(key == value) valStr = keyStr; else if (value!=Py_None) { if(!PyUnicode_Check(value)) { PyErr_SetString(PyExc_TypeError, "value must be unicode string"); return false; } valStr = PyUnicode_AsUTF8(value); } App::Property *prop = nullptr; auto &info = it->second; if(valStr) { auto pIt = propMap.find(valStr); if(pIt == propMap.end()) { str << "cannot find property '" << valStr << "'"; PyErr_SetString(PyExc_ValueError, str.str().c_str()); return false; } prop = pIt->second; if(!prop->isDerivedFrom(info.type)) { str << "expect property '" << keyStr << "(" << valStr << ") to be derived from '" << info.type.getName() << "', instead of '" << prop->getTypeId().getName() << "'"; PyErr_SetString(PyExc_TypeError, str.str().c_str()); } } props[keyStr] = std::make_pair(info.index,prop); return true; } PyObject* LinkBaseExtensionPy::configLinkProperty(PyObject *args, PyObject *keywds) { auto ext = getLinkBaseExtensionPtr(); const auto &info = ext->getPropertyInfoMap(); PropMap propMap; ext->getExtendedContainer()->getPropertyMap(propMap); PropTmpMap props; if(args && PyTuple_Check(args)) { for(Py_ssize_t pos=0;possetProperty(v.second.first,v.second.second); Py_Return; } PyObject* LinkBaseExtensionPy::getLinkExtProperty(PyObject *args) { const char *name; if(!PyArg_ParseTuple(args,"s",&name)) return nullptr; auto prop = getLinkBaseExtensionPtr()->getProperty(name); if(!prop) { PyErr_SetString(PyExc_AttributeError, "unknown property name"); return nullptr; } return prop->getPyObject(); } PyObject* LinkBaseExtensionPy::getLinkExtPropertyName(PyObject *args) { const char *name; if(!PyArg_ParseTuple(args,"s",&name)) return nullptr; auto prop = getLinkBaseExtensionPtr()->getProperty(name); if(!prop) { PyErr_SetString(PyExc_AttributeError, "unknown property name"); return nullptr; } auto container = getLinkBaseExtensionPtr()->getExtendedContainer(); if(!container) { PyErr_SetString(PyExc_RuntimeError, "no extended container"); return nullptr; } name = container->getPropertyName(prop); if(!name) { PyErr_SetString(PyExc_RuntimeError, "cannot find property name"); return nullptr; } return Py::new_reference_to(Py::String(name)); } PyObject* LinkBaseExtensionPy::getLinkPropertyInfo(PyObject *args) { auto ext = getLinkBaseExtensionPtr(); const auto &infos = ext->getPropertyInfo(); if(PyArg_ParseTuple(args,"")) { Py::Tuple ret(infos.size()); int i=0; for(const auto &info : infos) { ret.setItem(i++,Py::TupleN(Py::String(info.name), Py::String(info.type.getName()),Py::String(info.doc))); } return Py::new_reference_to(ret); } short index = 0; if(PyArg_ParseTuple(args,"h",&index)) { if(index<0 || index>=(int)infos.size()) { PyErr_SetString(PyExc_ValueError, "index out of range"); return nullptr; } Py::TupleN ret(Py::String(infos[index].name), Py::String(infos[index].type.getName()),Py::String(infos[index].doc)); return Py::new_reference_to(ret); } char *name; if(PyArg_ParseTuple(args,"s",&name)) { for(const auto & info : infos) { if(strcmp(info.name,name)==0) { Py::TupleN ret(Py::String(info.type.getName()), Py::String(info.doc)); return Py::new_reference_to(ret); } } PyErr_SetString(PyExc_ValueError, "unknown property name"); return nullptr; } PyErr_SetString(PyExc_ValueError, "invalid arguments"); return nullptr; } void parseLink(LinkBaseExtension *ext, int index, PyObject *value) { App::DocumentObject *obj = nullptr; PropertyStringList subs; PropertyString sub; if(value!=Py_None) { if(PyObject_TypeCheck(value,&DocumentObjectPy::Type)) { obj = static_cast(value)->getDocumentObjectPtr(); }else if(!PySequence_Check(value)) throw Base::TypeError("Expects type of DocumentObject or sequence"); else{ Py::Sequence seq(value); if(seq[0].ptr() != Py_None) { if(!PyObject_TypeCheck(seq[0].ptr(),&DocumentObjectPy::Type)) throw Base::TypeError("Expects the first argument to be DocumentObject in sequence"); obj = static_cast(seq[0].ptr())->getDocumentObjectPtr(); if(seq.size()>1) { sub.setPyObject(seq[1].ptr()); if(seq.size()>2) subs.setPyObject(seq[2].ptr()); } } } } ext->setLink(index,obj,sub.getValue(),subs.getValue()); } PyObject* LinkBaseExtensionPy::setLink(PyObject *_args) { Py::Sequence args(_args); PY_TRY { auto ext = getLinkBaseExtensionPtr(); PyObject *pcObj = args.size()?args[0].ptr():Py_None; if(pcObj == Py_None) { ext->setLink(-1,nullptr); }else if(PyDict_Check(pcObj)) { PyObject *key, *value; Py_ssize_t pos = 0; while(PyDict_Next(pcObj, &pos, &key, &value)) parseLink(ext,Py::Int(key),value); }else if(PySequence_Check(pcObj)) { ext->setLink(-1,nullptr); Py::Sequence seq(pcObj); for(Py_ssize_t i=0;icacheChildLabel(Base::asBoolean(enable) ? -1 : 0); Py_Return; }PY_CATCH; } PyObject* LinkBaseExtensionPy::flattenSubname(PyObject *args) { const char *subname; if(!PyArg_ParseTuple(args,"s",&subname)) return nullptr; PY_TRY { return Py::new_reference_to(Py::String( getLinkBaseExtensionPtr()->flattenSubname(subname))); }PY_CATCH; } PyObject* LinkBaseExtensionPy::expandSubname(PyObject *args) { const char *subname; if(!PyArg_ParseTuple(args,"s",&subname)) return nullptr; PY_TRY { std::string sub(subname); getLinkBaseExtensionPtr()->expandSubname(sub); return Py::new_reference_to(Py::String(sub)); }PY_CATCH; } Py::List LinkBaseExtensionPy::getLinkedChildren() const { Py::List ret; for(auto o : getLinkBaseExtensionPtr()->getLinkedChildren(true)) ret.append(Py::asObject(o->getPyObject())); return ret; } PyObject *LinkBaseExtensionPy::getCustomAttributes(const char* /*attr*/) const { return nullptr; } int LinkBaseExtensionPy::setCustomAttributes(const char* /*attr*/, PyObject * /*obj*/) { return 0; }