1
/****************************************************************************
2
* Copyright (c) 2017 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
****************************************************************************/
23
#include "PreCompiled.h"
29
#include "DocumentObjectPy.h"
30
#include "LinkBaseExtensionPy.h"
31
#include "LinkBaseExtensionPy.cpp"
35
// returns a string which represent the object e.g. when printed in python
36
std::string LinkBaseExtensionPy::representation() const
38
std::ostringstream str;
39
str << "<" << getLinkBaseExtensionPtr()->getExtensionClassTypeId().getName() << ">";
43
using PropTmpMap = std::map<std::string, std::pair<int,Property*> >;
44
using PropMap = std::map<std::string, Property*>;
46
static bool getProperty(PropTmpMap &props, const LinkBaseExtension::PropInfoMap &infoMap,
47
const PropMap &propMap, PyObject *key, PyObject *value)
49
std::ostringstream str;
51
if(!PyUnicode_Check(key)) {
52
PyErr_SetString(PyExc_TypeError, "key must be a unicode string");
55
const char *keyStr = PyUnicode_AsUTF8(key);
56
auto it = infoMap.find(keyStr);
57
if(it == infoMap.end()){
58
str << "unknown key '" << keyStr << "'";
59
PyErr_SetString(PyExc_KeyError, str.str().c_str());
63
const char *valStr = nullptr;
66
else if (value!=Py_None) {
67
if(!PyUnicode_Check(value)) {
68
PyErr_SetString(PyExc_TypeError, "value must be unicode string");
71
valStr = PyUnicode_AsUTF8(value);
74
App::Property *prop = nullptr;
75
auto &info = it->second;
77
auto pIt = propMap.find(valStr);
78
if(pIt == propMap.end()) {
79
str << "cannot find property '" << valStr << "'";
80
PyErr_SetString(PyExc_ValueError, str.str().c_str());
84
if(!prop->isDerivedFrom(info.type)) {
85
str << "expect property '" << keyStr << "(" << valStr
86
<< ") to be derived from '" << info.type.getName()
87
<< "', instead of '" << prop->getTypeId().getName() << "'";
88
PyErr_SetString(PyExc_TypeError, str.str().c_str());
91
props[keyStr] = std::make_pair(info.index,prop);
95
PyObject* LinkBaseExtensionPy::configLinkProperty(PyObject *args, PyObject *keywds) {
96
auto ext = getLinkBaseExtensionPtr();
97
const auto &info = ext->getPropertyInfoMap();
100
ext->getExtendedContainer()->getPropertyMap(propMap);
104
if(args && PyTuple_Check(args)) {
105
for(Py_ssize_t pos=0;pos<PyTuple_GET_SIZE(args);++pos) {
106
auto key = PyTuple_GET_ITEM(args,pos);
107
if(!getProperty(props,info,propMap,key,key))
111
if(keywds && PyDict_Check(keywds)) {
112
PyObject *key, *value;
114
while (PyDict_Next(keywds, &pos, &key, &value)) {
115
if(!getProperty(props,info,propMap,key,value))
120
ext->setProperty(v.second.first,v.second.second);
124
PyObject* LinkBaseExtensionPy::getLinkExtProperty(PyObject *args)
127
if(!PyArg_ParseTuple(args,"s",&name))
129
auto prop = getLinkBaseExtensionPtr()->getProperty(name);
131
PyErr_SetString(PyExc_AttributeError, "unknown property name");
134
return prop->getPyObject();
137
PyObject* LinkBaseExtensionPy::getLinkExtPropertyName(PyObject *args) {
139
if(!PyArg_ParseTuple(args,"s",&name))
141
auto prop = getLinkBaseExtensionPtr()->getProperty(name);
143
PyErr_SetString(PyExc_AttributeError, "unknown property name");
146
auto container = getLinkBaseExtensionPtr()->getExtendedContainer();
148
PyErr_SetString(PyExc_RuntimeError, "no extended container");
151
name = container->getPropertyName(prop);
153
PyErr_SetString(PyExc_RuntimeError, "cannot find property name");
156
return Py::new_reference_to(Py::String(name));
159
PyObject* LinkBaseExtensionPy::getLinkPropertyInfo(PyObject *args)
161
auto ext = getLinkBaseExtensionPtr();
163
const auto &infos = ext->getPropertyInfo();
165
if(PyArg_ParseTuple(args,"")) {
166
Py::Tuple ret(infos.size());
168
for(const auto &info : infos) {
169
ret.setItem(i++,Py::TupleN(Py::String(info.name),
170
Py::String(info.type.getName()),Py::String(info.doc)));
172
return Py::new_reference_to(ret);
176
if(PyArg_ParseTuple(args,"h",&index)) {
177
if(index<0 || index>=(int)infos.size()) {
178
PyErr_SetString(PyExc_ValueError, "index out of range");
181
Py::TupleN ret(Py::String(infos[index].name),
182
Py::String(infos[index].type.getName()),Py::String(infos[index].doc));
183
return Py::new_reference_to(ret);
187
if(PyArg_ParseTuple(args,"s",&name)) {
188
for(const auto & info : infos) {
189
if(strcmp(info.name,name)==0) {
190
Py::TupleN ret(Py::String(info.type.getName()),
191
Py::String(info.doc));
192
return Py::new_reference_to(ret);
195
PyErr_SetString(PyExc_ValueError, "unknown property name");
199
PyErr_SetString(PyExc_ValueError, "invalid arguments");
203
void parseLink(LinkBaseExtension *ext, int index, PyObject *value) {
204
App::DocumentObject *obj = nullptr;
205
PropertyStringList subs;
208
if(PyObject_TypeCheck(value,&DocumentObjectPy::Type)) {
209
obj = static_cast<DocumentObjectPy*>(value)->getDocumentObjectPtr();
210
}else if(!PySequence_Check(value))
211
throw Base::TypeError("Expects type of DocumentObject or sequence");
213
Py::Sequence seq(value);
214
if(seq[0].ptr() != Py_None) {
215
if(!PyObject_TypeCheck(seq[0].ptr(),&DocumentObjectPy::Type))
216
throw Base::TypeError("Expects the first argument to be DocumentObject in sequence");
217
obj = static_cast<DocumentObjectPy*>(seq[0].ptr())->getDocumentObjectPtr();
219
sub.setPyObject(seq[1].ptr());
221
subs.setPyObject(seq[2].ptr());
226
ext->setLink(index,obj,sub.getValue(),subs.getValue());
229
PyObject* LinkBaseExtensionPy::setLink(PyObject *_args)
231
Py::Sequence args(_args);
233
auto ext = getLinkBaseExtensionPtr();
234
PyObject *pcObj = args.size()?args[0].ptr():Py_None;
235
if(pcObj == Py_None) {
236
ext->setLink(-1,nullptr);
237
}else if(PyDict_Check(pcObj)) {
238
PyObject *key, *value;
240
while(PyDict_Next(pcObj, &pos, &key, &value))
241
parseLink(ext,Py::Int(key),value);
242
}else if(PySequence_Check(pcObj)) {
243
ext->setLink(-1,nullptr);
244
Py::Sequence seq(pcObj);
245
for(Py_ssize_t i=0;i<seq.size();++i)
246
parseLink(ext,i,seq[i].ptr());
248
parseLink(ext,-1,_args);
254
PyObject* LinkBaseExtensionPy::cacheChildLabel(PyObject *args) {
255
PyObject *enable = Py_True;
256
if(!PyArg_ParseTuple(args,"|O",&enable))
259
getLinkBaseExtensionPtr()->cacheChildLabel(Base::asBoolean(enable) ? -1 : 0);
264
PyObject* LinkBaseExtensionPy::flattenSubname(PyObject *args) {
266
if(!PyArg_ParseTuple(args,"s",&subname))
269
return Py::new_reference_to(Py::String(
270
getLinkBaseExtensionPtr()->flattenSubname(subname)));
274
PyObject* LinkBaseExtensionPy::expandSubname(PyObject *args) {
276
if(!PyArg_ParseTuple(args,"s",&subname))
279
std::string sub(subname);
280
getLinkBaseExtensionPtr()->expandSubname(sub);
281
return Py::new_reference_to(Py::String(sub));
285
Py::List LinkBaseExtensionPy::getLinkedChildren() const {
287
for(auto o : getLinkBaseExtensionPtr()->getLinkedChildren(true))
288
ret.append(Py::asObject(o->getPyObject()));
292
PyObject *LinkBaseExtensionPy::getCustomAttributes(const char* /*attr*/) const
297
int LinkBaseExtensionPy::setCustomAttributes(const char* /*attr*/, PyObject * /*obj*/)