/*************************************************************************** * Copyright (c) 2006 Werner Mayer * * * * 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 #include #include #include #include #include #include #include #include #include #include #include #include "ViewProviderFeaturePython.h" #include "Application.h" #include "BitmapFactory.h" #include "Document.h" #include "PythonWrapper.h" #include "View3DInventorViewer.h" #include "ViewProviderDocumentObjectPy.h" #include "Selection.h" FC_LOG_LEVEL_INIT("ViewProviderFeaturePython", true, true) using namespace Gui; namespace sp = std::placeholders; // ---------------------------------------------------------------------------- ViewProviderFeaturePythonImp::ViewProviderFeaturePythonImp( ViewProviderDocumentObject* vp, App::PropertyPythonObject& proxy ) : object(vp) , Proxy(proxy) {} ViewProviderFeaturePythonImp::~ViewProviderFeaturePythonImp() { Base::PyGILStateLocker lock; #undef FC_PY_ELEMENT #define FC_PY_ELEMENT(_name) py_##_name = Py::None(); try { FC_PY_VIEW_OBJECT } catch (Py::Exception& e) { e.clear(); } this->selectionObserver.~SelectionObserverPythonHandler(); } void ViewProviderFeaturePythonImp::init(PyObject* pyobj) { Base::PyGILStateLocker lock; has__object__ = !!PyObject_HasAttrString(pyobj, "__object__"); #undef FC_PY_ELEMENT #define FC_PY_ELEMENT(_name) FC_PY_ELEMENT_INIT(_name) FC_PY_VIEW_OBJECT this->selectionObserver.init(pyobj); } #define FC_PY_CALL_CHECK(_name) _FC_PY_CALL_CHECK(_name, return (NotImplemented)) QIcon ViewProviderFeaturePythonImp::getIcon() const { _FC_PY_CALL_CHECK(getIcon, return (QIcon())); // Run the getIcon method of the proxy object. Base::PyGILStateLocker lock; try { Py::Object ret(Base::pyCall(py_getIcon.ptr())); if (ret.isNone()) { return {}; } if (ret.isString()) { std::string content = Py::String(ret).as_std_string("utf-8"); QPixmap icon; if (BitmapFactory().findPixmapInCache(content.c_str(), icon)) { return icon; } // Check if the passed string is a filename, otherwise treat as xpm data QFileInfo fi(QString::fromUtf8(content.c_str())); if (fi.isFile() && fi.exists()) { icon.load(fi.absoluteFilePath()); } else { QByteArray ary; int strlen = (int)content.size(); ary.resize(strlen); for (int j = 0; j < strlen; j++) { ary[j] = content[j]; } // Make sure to remove crap around the XPM data QList lines = ary.split('\n'); QByteArray buffer; buffer.reserve(ary.size() + lines.size()); for (const auto& line : lines) { QByteArray trim = line.trimmed(); if (!trim.isEmpty()) { buffer.append(trim); buffer.append('\n'); } } icon.loadFromData(buffer, "XPM"); } if (!icon.isNull()) { return icon; } } else { PythonWrapper wrap; wrap.loadGuiModule(); wrap.loadWidgetsModule(); QIcon* picon = wrap.toQIcon(ret.ptr()); if (picon) { return *picon; } } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); } else { Base::PyException e; // extract the Python error text e.reportException(); } } return {}; } std::map ViewProviderFeaturePythonImp::getOverlayIcons() const { std::map overlays; _FC_PY_CALL_CHECK(getOverlayIcons, return overlays); Base::PyGILStateLocker lock; try { Py::Object ret(Base::pyCall(py_getOverlayIcons.ptr())); if (ret.isNone()) { return overlays; } // Expect a dictionary (dict) from Python if (!PyDict_Check(ret.ptr())) { return overlays; } Py::Dict dict(ret); PyObject *key, *value; Py_ssize_t pos = 0; // Iterate over the dictionary items while (PyDict_Next(dict.ptr(), &pos, &key, &value)) { // Key should be an integer (from the enum) if (!PyLong_Check(key)) { continue; } // Value should be a string if (!PyUnicode_Check(value)) { continue; } long position_val = PyLong_AsLong(key); // Basic validation for the enum range if (position_val >= BitmapFactoryInst::TopLeft && position_val <= BitmapFactoryInst::BottomRight) { auto position = static_cast(position_val); std::string iconName = Py::String(value).as_std_string("utf-8"); if (!iconName.empty()) { overlays[position] = iconName; } } } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); } else { Base::PyException e; e.reportException(); } } return overlays; } bool ViewProviderFeaturePythonImp::claimChildren(std::vector& children) const { _FC_PY_CALL_CHECK(claimChildren, return (false)); Base::PyGILStateLocker lock; try { Py::Sequence list(Base::pyCall(py_claimChildren.ptr())); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { PyObject* item = (*it).ptr(); if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) { App::DocumentObject* obj = static_cast(item)->getDocumentObjectPtr(); children.push_back(obj); } } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return false; } Base::PyException e; // extract the Python error text e.reportException(); } return true; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::useNewSelectionModel() const { FC_PY_CALL_CHECK(useNewSelectionModel); // Run the useNewSelectionModel method of the proxy object. Base::PyGILStateLocker lock; try { Py::Boolean ok(Py::Callable(py_useNewSelectionModel).apply(Py::Tuple())); return ok ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Accepted; } void ViewProviderFeaturePythonImp::onSelectionChanged(const SelectionChanges& changes) { this->selectionObserver.handleSelectionChanged(changes); } bool ViewProviderFeaturePythonImp::getElement(const SoDetail* det, std::string& res) const { _FC_PY_CALL_CHECK(getElement, return (false)); // Run the onChanged method of the proxy object. Base::PyGILStateLocker lock; try { PyObject* pivy = nullptr; // Note: As there is no ref'counting mechanism for the SoDetail class we must // pass '0' as the last parameter so that the Python object does not 'own' // the detail object. pivy = Base::Interpreter().createSWIGPointerObj( "pivy.coin", "SoDetail *", const_cast(static_cast(det)), 0 ); Py::Tuple args(1); args.setItem(0, Py::Object(pivy, true)); Py::String name(Base::pyCall(py_getElement.ptr(), args.ptr())); res = name; return true; } catch (const Base::Exception& e) { e.reportException(); } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return false; } Base::PyException e; // extract the Python error text e.reportException(); } return true; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::getElementPicked( const SoPickedPoint* pp, std::string& subname ) const { FC_PY_CALL_CHECK(getElementPicked); Base::PyGILStateLocker lock; try { PyObject* pivy = nullptr; pivy = Base::Interpreter().createSWIGPointerObj( "pivy.coin", "SoPickedPoint *", const_cast(static_cast(pp)), 0 ); Py::Tuple args(1); args.setItem(0, Py::Object(pivy, true)); Py::Object ret(Base::pyCall(py_getElementPicked.ptr(), args.ptr())); if (!ret.isString()) { return Rejected; } subname = ret.as_string(); return Accepted; } catch (const Base::Exception& e) { e.reportException(); } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } bool ViewProviderFeaturePythonImp::getDetail(const char* name, SoDetail*& det) const { _FC_PY_CALL_CHECK(getDetail, return (false)); // Run the onChanged method of the proxy object. Base::PyGILStateLocker lock; try { Py::Tuple args(1); args.setItem(0, Py::String(name)); Py::Object pydet(Base::pyCall(py_getDetail.ptr(), args.ptr())); void* ptr = nullptr; Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoDetail *", pydet.ptr(), &ptr, 0); auto detail = static_cast(ptr); det = detail ? detail->copy() : nullptr; return true; } catch (const Base::Exception& e) { e.reportException(); } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return false; } Base::PyException e; // extract the Python error text e.reportException(); } return true; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::getDetailPath( const char* name, SoFullPath* path, bool append, SoDetail*& det ) const { FC_PY_CALL_CHECK(getDetailPath); Base::PyGILStateLocker lock; auto length = path->getLength(); try { PyObject* pivy = nullptr; pivy = Base::Interpreter() .createSWIGPointerObj("pivy.coin", "SoFullPath *", static_cast(path), 1); path->ref(); Py::Tuple args(3); args.setItem(0, Py::String(name)); args.setItem(1, Py::Object(pivy, true)); args.setItem(2, Py::Boolean(append)); Py::Object pyDet(Base::pyCall(py_getDetailPath.ptr(), args.ptr())); if (!pyDet.isTrue()) { return Rejected; } if (pyDet.isBoolean()) { return Accepted; } void* ptr = nullptr; Base::Interpreter().convertSWIGPointerObj("pivy.coin", "SoDetail *", pyDet.ptr(), &ptr, 0); auto detail = static_cast(ptr); det = detail ? detail->copy() : nullptr; if (det) { return Accepted; } delete det; } catch (const Base::Exception& e) { e.reportException(); } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } path->truncate(length); return Rejected; } std::vector ViewProviderFeaturePythonImp::getSelectionShape(const char* /*Element*/) const { return {}; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::setEdit(int ModNum) { FC_PY_CALL_CHECK(setEdit) Base::PyGILStateLocker lock; try { if (has__object__) { Py::Tuple args(1); args.setItem(0, Py::Long(ModNum)); Py::Object ret(Base::pyCall(py_setEdit.ptr(), args.ptr())); if (ret.isNone()) { return NotImplemented; } Py::Boolean ok(ret); bool value = static_cast(ok); return value ? Accepted : Rejected; } else { Py::Tuple args(2); args.setItem(0, Py::Object(object->getPyObject(), true)); args.setItem(1, Py::Long(ModNum)); Py::Object ret(Base::pyCall(py_setEdit.ptr(), args.ptr())); if (ret.isNone()) { return NotImplemented; } Py::Boolean ok(ret); bool value = static_cast(ok); return value ? Accepted : Rejected; } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::unsetEdit(int ModNum) { FC_PY_CALL_CHECK(unsetEdit) Base::PyGILStateLocker lock; try { if (has__object__) { Py::Tuple args(1); args.setItem(0, Py::Long(ModNum)); Py::Object ret(Base::pyCall(py_unsetEdit.ptr(), args.ptr())); if (ret.isNone()) { return NotImplemented; } Py::Boolean ok(ret); bool value = static_cast(ok); return value ? Accepted : Rejected; } else { Py::Tuple args(2); args.setItem(0, Py::Object(object->getPyObject(), true)); args.setItem(1, Py::Long(ModNum)); Py::Object ret(Base::pyCall(py_unsetEdit.ptr(), args.ptr())); if (ret.isNone()) { return NotImplemented; } Py::Boolean ok(ret); bool value = static_cast(ok); return value ? Accepted : Rejected; } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::setEditViewer( View3DInventorViewer* viewer, int ModNum ) { FC_PY_CALL_CHECK(setEditViewer) Base::PyGILStateLocker lock; try { Py::Tuple args(3); args.setItem(0, Py::Object(object->getPyObject(), true)); args.setItem(1, Py::Object(viewer->getPyObject(), true)); args.setItem(2, Py::Long(ModNum)); Py::Object ret(Base::pyCall(py_setEditViewer.ptr(), args.ptr())); return ret.isTrue() ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::unsetEditViewer( View3DInventorViewer* viewer ) { FC_PY_CALL_CHECK(unsetEditViewer) // Run the onChanged method of the proxy object. Base::PyGILStateLocker lock; try { Py::Tuple args(2); args.setItem(0, Py::Object(object->getPyObject(), true)); args.setItem(1, Py::Object(viewer->getPyObject(), true)); Py::Object ret(Base::pyCall(py_unsetEditViewer.ptr(), args.ptr())); return ret.isTrue() ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::doubleClicked() { FC_PY_CALL_CHECK(doubleClicked) // Run the onChanged method of the proxy object. Base::PyGILStateLocker lock; try { if (has__object__) { Py::Boolean ok(Base::pyCall(py_doubleClicked.ptr())); bool value = (bool)ok; return value ? Accepted : Rejected; } else { Py::Tuple args(1); args.setItem(0, Py::Object(object->getPyObject(), true)); Py::Boolean ok(Base::pyCall(py_doubleClicked.ptr(), args.ptr())); bool value = (bool)ok; return value ? Accepted : Rejected; } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } bool ViewProviderFeaturePythonImp::setupContextMenu(QMenu* menu) { _FC_PY_CALL_CHECK(setupContextMenu, return (false)); // Run the attach method of the proxy object. Base::PyGILStateLocker lock; try { if (has__object__) { PythonWrapper wrap; wrap.loadGuiModule(); wrap.loadWidgetsModule(); Py::Tuple args(1); args.setItem(0, wrap.fromQWidget(menu, "QMenu")); return Base::pyCall(py_setupContextMenu.ptr(), args.ptr()).isTrue(); } else { PythonWrapper wrap; wrap.loadGuiModule(); wrap.loadWidgetsModule(); Py::Tuple args(2); args.setItem(0, Py::Object(object->getPyObject(), true)); args.setItem(1, wrap.fromQWidget(menu, "QMenu")); return Base::pyCall(py_setupContextMenu.ptr(), args.ptr()).isTrue(); } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return false; } Base::PyException e; // extract the Python error text e.reportException(); } return true; } void ViewProviderFeaturePythonImp::attach(App::DocumentObject* pcObject) { _FC_PY_CALL_CHECK(attach, return); // Run the attach method of the proxy object. Base::PyGILStateLocker lock; try { if (has__object__) { Base::pyCall(py_attach.ptr()); } else { Py::Tuple args(1); args.setItem(0, Py::Object(object->getPyObject(), true)); Base::pyCall(py_attach.ptr(), args.ptr()); } // #0000415: Now simulate a property change event to call // claimChildren if implemented. pcObject->Label.touch(); } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } } void ViewProviderFeaturePythonImp::updateData(const App::Property* prop) { if (py_updateData.isNone()) { return; } // Run the updateData method of the proxy object. Base::PyGILStateLocker lock; try { if (has__object__) { Py::Tuple args(1); const char* prop_name = object->getObject()->getPropertyName(prop); if (prop_name) { args.setItem(0, Py::String(prop_name)); Base::pyCall(py_updateData.ptr(), args.ptr()); } } else { Py::Tuple args(2); args.setItem(0, Py::Object(object->getObject()->getPyObject(), true)); const char* prop_name = object->getObject()->getPropertyName(prop); if (prop_name) { args.setItem(1, Py::String(prop_name)); Base::pyCall(py_updateData.ptr(), args.ptr()); } } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } } void ViewProviderFeaturePythonImp::onChanged(const App::Property* prop) { if (py_onChanged.isNone()) { return; } // Run the onChanged method of the proxy object. Base::PyGILStateLocker lock; try { if (has__object__) { Py::Tuple args(1); const char* prop_name = object->getPropertyName(prop); if (prop_name) { args.setItem(0, Py::String(prop_name)); Base::pyCall(py_onChanged.ptr(), args.ptr()); } } else { Py::Tuple args(2); args.setItem(0, Py::Object(object->getPyObject(), true)); const char* prop_name = object->getPropertyName(prop); if (prop_name) { args.setItem(1, Py::String(prop_name)); Base::pyCall(py_onChanged.ptr(), args.ptr()); } } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } } void ViewProviderFeaturePythonImp::onBeforeChange(const App::Property* prop) { if (py_onBeforeChange.isNone()) { return; } // Run the onChanged method of the proxy object. Base::PyGILStateLocker lock; try { if (has__object__) { Py::Tuple args(1); const char* prop_name = object->getPropertyName(prop); if (prop_name) { args.setItem(0, Py::String(prop_name)); Base::pyCall(py_onBeforeChange.ptr(), args.ptr()); } } else { Py::Tuple args(2); args.setItem(0, Py::Object(object->getPyObject(), true)); const char* prop_name = object->getPropertyName(prop); if (prop_name) { args.setItem(1, Py::String(prop_name)); Base::pyCall(py_onBeforeChange.ptr(), args.ptr()); } } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } } void ViewProviderFeaturePythonImp::startRestoring() {} void ViewProviderFeaturePythonImp::finishRestoring() { Base::PyGILStateLocker lock; try { Py::Object vp = Proxy.getValue(); if (vp.isNone()) { object->show(); Proxy.setValue(Py::Long(1)); } else { _FC_PY_CALL_CHECK(finishRestoring, return); Base::pyCall(py_finishRestoring.ptr()); } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } } void ViewProviderFeaturePythonImp::beforeDelete() { _FC_PY_CALL_CHECK(beforeDelete, return); Base::PyGILStateLocker lock; try { if (has__object__) { Base::pyCall(py_beforeDelete.ptr()); } else { Py::Tuple args(1); args.setItem(0, Py::Object(object->getPyObject(), true)); Base::pyCall(py_beforeDelete.ptr(), args.ptr()); } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); } else { Base::PyException e; e.reportException(); } } } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::onDelete( const std::vector& sub ) { FC_PY_CALL_CHECK(onDelete); Base::PyGILStateLocker lock; try { Py::Tuple seq(sub.size()); int index = 0; for (const auto& it : sub) { seq.setItem(index++, Py::String(it)); } if (has__object__) { Py::Tuple args(1); args.setItem(0, seq); Py::Boolean ok(Base::pyCall(py_onDelete.ptr(), args.ptr())); return ok ? Accepted : Rejected; } else { Py::Tuple args(2); args.setItem(0, Py::Object(object->getPyObject(), true)); args.setItem(1, seq); Py::Boolean ok(Base::pyCall(py_onDelete.ptr(), args.ptr())); return ok ? Accepted : Rejected; } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); return Rejected; } } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::canDelete( App::DocumentObject* obj ) const { FC_PY_CALL_CHECK(canDelete); Base::PyGILStateLocker lock; try { Py::Tuple args(1); args.setItem(0, obj ? Py::Object(obj->getPyObject(), true) : Py::Object()); return Py::Boolean(Base::pyCall(py_canDelete.ptr(), args.ptr())) ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); return Rejected; } } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::canAddToSceneGraph() const { FC_PY_CALL_CHECK(canAddToSceneGraph); Base::PyGILStateLocker lock; try { return Py::Boolean(Py::Callable(py_canAddToSceneGraph).apply(Py::Tuple())) ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Accepted; } bool ViewProviderFeaturePythonImp::getDefaultDisplayMode(std::string& mode) const { _FC_PY_CALL_CHECK(getDefaultDisplayMode, return (0)); // Run the getDefaultDisplayMode method of the proxy object. Base::PyGILStateLocker lock; try { Py::String str(Base::pyCall(py_getDefaultDisplayMode.ptr())); mode = str.as_std_string("ascii"); return true; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return false; } Base::PyException e; // extract the Python error text e.reportException(); } return true; } std::vector ViewProviderFeaturePythonImp::getDisplayModes() const { std::vector modes; _FC_PY_CALL_CHECK(getDisplayModes, return (modes)); // Run the getDisplayModes method of the proxy object. Base::PyGILStateLocker lock; try { if (has__object__) { Py::Sequence list(Base::pyCall(py_getDisplayModes.ptr())); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { Py::String str(*it); modes.push_back(str.as_std_string("ascii")); } } else { Py::Tuple args(1); args.setItem(0, Py::Object(object->getPyObject(), true)); Py::Sequence list(Base::pyCall(py_getDisplayModes.ptr(), args.ptr())); for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { Py::String str(*it); modes.push_back(str.as_std_string("ascii")); } } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); } else { Base::PyException e; // extract the Python error text e.reportException(); } } return modes; } std::string ViewProviderFeaturePythonImp::setDisplayMode(const char* ModeName) { _FC_PY_CALL_CHECK(setDisplayMode, return (ModeName)); // Run the setDisplayMode method of the proxy object. Base::PyGILStateLocker lock; try { Py::Tuple args(1); args.setItem(0, Py::String(ModeName)); Py::String str(Base::pyCall(py_setDisplayMode.ptr(), args.ptr())); return str.as_std_string("ascii"); } catch (Py::Exception&) { Base::PyException e; // extract the Python error text e.reportException(); } return ModeName; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::canDragObjects() const { FC_PY_CALL_CHECK(canDragObjects); Base::PyGILStateLocker lock; try { Py::Boolean ok(Base::pyCall(py_canDragObjects.ptr())); return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::canDragObject( App::DocumentObject* obj ) const { FC_PY_CALL_CHECK(canDragObject); Base::PyGILStateLocker lock; try { Py::Tuple args(1); args.setItem(0, Py::Object(obj->getPyObject(), true)); Py::Boolean ok(Base::pyCall(py_canDragObject.ptr(), args.ptr())); return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::dragObject(App::DocumentObject* obj) { FC_PY_CALL_CHECK(dragObject); // Run the onChanged method of the proxy object. Base::PyGILStateLocker lock; try { if (has__object__) { Py::Tuple args(1); args.setItem(0, Py::Object(obj->getPyObject(), true)); Base::pyCall(py_dragObject.ptr(), args.ptr()); return Accepted; } else { Py::Tuple args(2); args.setItem(0, Py::Object(object->getPyObject(), true)); args.setItem(1, Py::Object(obj->getPyObject(), true)); Base::pyCall(py_dragObject.ptr(), args.ptr()); return Accepted; } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::canDropObjects() const { FC_PY_CALL_CHECK(canDropObjects); Base::PyGILStateLocker lock; try { Py::Boolean ok(Base::pyCall(py_canDropObjects.ptr())); return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::canDropObject( App::DocumentObject* obj ) const { FC_PY_CALL_CHECK(canDropObject); Base::PyGILStateLocker lock; try { Py::Tuple args(1); args.setItem(0, Py::Object(obj->getPyObject(), true)); Py::Boolean ok(Base::pyCall(py_canDropObject.ptr(), args.ptr())); return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::dropObject(App::DocumentObject* obj) { FC_PY_CALL_CHECK(dropObject); Base::PyGILStateLocker lock; try { if (has__object__) { Py::Tuple args(1); args.setItem(0, Py::Object(obj->getPyObject(), true)); Base::pyCall(py_dropObject.ptr(), args.ptr()); return Accepted; } else { Py::Tuple args(2); args.setItem(0, Py::Object(object->getPyObject(), true)); args.setItem(1, Py::Object(obj->getPyObject(), true)); Base::pyCall(py_dropObject.ptr(), args.ptr()); return Accepted; } } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException::throwException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::canDragAndDropObject( App::DocumentObject* obj ) const { FC_PY_CALL_CHECK(canDragAndDropObject); Base::PyGILStateLocker lock; try { Py::TupleN args(Py::Object(obj->getPyObject(), true)); Py::Boolean ok(Base::pyCall(py_canDragAndDropObject.ptr(), args.ptr())); return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::canDropObjectEx( App::DocumentObject* obj, App::DocumentObject* owner, const char* subname, const std::vector& elements ) const { FC_PY_CALL_CHECK(canDropObjectEx); Base::PyGILStateLocker lock; try { Py::Tuple args(4); args.setItem(0, Py::Object(obj->getPyObject(), true)); args.setItem(1, owner ? Py::Object(owner->getPyObject(), true) : Py::None()); args.setItem(2, Py::String(subname ? subname : "")); Py::Tuple tuple(elements.size()); int i = 0; for (auto& element : elements) { tuple.setItem(i++, Py::String(element)); } args.setItem(3, tuple); Py::Boolean ok(Base::pyCall(py_canDropObjectEx.ptr(), args.ptr())); return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } bool ViewProviderFeaturePythonImp::dropObjectEx( App::DocumentObject* obj, App::DocumentObject* owner, const char* subname, const std::vector& elements, std::string& ret ) { _FC_PY_CALL_CHECK(dropObjectEx, return (false)); Base::PyGILStateLocker lock; try { Py::Tuple tuple(elements.size()); int i = 0; for (auto& element : elements) { tuple.setItem(i++, Py::String(element)); } Py::Object res; Py::TupleN args( Py::Object(object->getPyObject(), true), Py::Object(obj->getPyObject(), true), owner ? Py::Object(owner->getPyObject(), true) : Py::Object(), Py::String(subname ? subname : ""), tuple ); res = Base::pyCall(py_dropObjectEx.ptr(), args.ptr()); if (!res.isNone()) { ret = res.as_string(); } return true; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return false; } Base::PyException::throwException(); } return true; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::isShow() const { FC_PY_CALL_CHECK(isShow); Base::PyGILStateLocker lock; try { Py::Boolean ok(Base::pyCall(py_isShow.ptr())); return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::canRemoveChildrenFromRoot() const { FC_PY_CALL_CHECK(canRemoveChildrenFromRoot); Base::PyGILStateLocker lock; try { Py::Boolean ok(Base::pyCall(py_canRemoveChildrenFromRoot.ptr())); return static_cast(ok) ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } bool ViewProviderFeaturePythonImp::getDropPrefix(std::string& prefix) const { _FC_PY_CALL_CHECK(getDropPrefix, return (false)); Base::PyGILStateLocker lock; try { Py::Object ret(Base::pyCall(py_getDropPrefix.ptr())); if (ret.isNone()) { return false; } prefix = ret.as_string(); return true; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return false; } Base::PyException e; // extract the Python error text e.reportException(); } return true; } ViewProviderFeaturePythonImp::ValueT ViewProviderFeaturePythonImp::replaceObject( App::DocumentObject* oldObj, App::DocumentObject* newObj ) { if (!oldObj || !oldObj->isAttachedToDocument() || !newObj || !newObj->isAttachedToDocument()) { return NotImplemented; } FC_PY_CALL_CHECK(replaceObject); Base::PyGILStateLocker lock; try { Py::TupleN args(Py::asObject(oldObj->getPyObject()), Py::asObject(newObj->getPyObject())); Py::Boolean ok(Base::pyCall(py_replaceObject.ptr(), args.ptr())); return ok ? Accepted : Rejected; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return NotImplemented; } Base::PyException e; // extract the Python error text e.reportException(); } return Rejected; } bool ViewProviderFeaturePythonImp::getLinkedViewProvider( ViewProviderDocumentObject*& vp, std::string* subname, bool recursive ) const { _FC_PY_CALL_CHECK(getLinkedViewProvider, return (false)); Base::PyGILStateLocker lock; try { Py::Tuple args(1); args.setItem(0, Py::Boolean(recursive)); Py::Object res(Base::pyCall(py_getLinkedViewProvider.ptr(), args.ptr())); if (res.isNone()) { return true; } if (PyObject_TypeCheck(res.ptr(), &ViewProviderDocumentObjectPy::Type)) { vp = static_cast(res.ptr()) ->getViewProviderDocumentObjectPtr(); return true; } else if (PySequence_Check(res.ptr()) && PySequence_Length(res.ptr()) == 2) { Py::Sequence seq(res); Py::Object item0(seq[0].ptr()); Py::Object item1(seq[1].ptr()); if (PyObject_TypeCheck(item0.ptr(), &ViewProviderDocumentObjectPy::Type) && item1.isString()) { if (subname) { *subname = Py::String(item1).as_std_string("utf-8"); } vp = static_cast(item0.ptr()) ->getViewProviderDocumentObjectPtr(); return true; } } FC_ERR("getLinkedViewProvider(): invalid return type, expects ViewObject or (ViewObject, subname)"); return true; } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return false; } Base::PyException e; // extract the Python error text e.reportException(); } return true; } bool ViewProviderFeaturePythonImp::editProperty(const char* name) { _FC_PY_CALL_CHECK(editProperty, return false); Base::PyGILStateLocker lock; try { Py::Tuple args(1); args.setItem(0, Py::String(name)); Py::Object ret(Base::pyCall(py_editProperty.ptr(), args.ptr())); return ret.isTrue(); } catch (Py::Exception&) { if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { PyErr_Clear(); return false; } Base::PyException e; // extract the Python error text e.reportException(); } return false; } // --------------------------------------------------------- namespace Gui { PROPERTY_SOURCE_TEMPLATE(Gui::ViewProviderFeaturePython, Gui::ViewProviderDocumentObject) // explicit template instantiation template class GuiExport ViewProviderFeaturePythonT; } // namespace Gui // --------------------------------------------------------- namespace Gui { PROPERTY_SOURCE_TEMPLATE(Gui::ViewProviderGeometryPython, Gui::ViewProviderGeometryObject) // explicit template instantiation template class GuiExport ViewProviderFeaturePythonT; } // namespace Gui