// SPDX-License-Identifier: LGPL-2.1-or-later /*************************************************************************** * Copyright (c) 2024 David Carter * * * * This file is part of FreeCAD. * * * * FreeCAD is free software: you can redistribute it and/or modify it * * under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 2.1 of the * * License, or (at your option) any later version. * * * * FreeCAD 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with FreeCAD. If not, see * * . * * * **************************************************************************/ #include #include #include #include #include #include #include #include "Exceptions.h" #include "ExternalManager.h" #include "MaterialLibrary.h" #include "MaterialLibraryPy.h" #include "MaterialManager.h" #include "MaterialPy.h" #include "ModelLibrary.h" #include "ModelManager.h" #include "ModelPy.h" #include "MaterialFilterPy.h" #include "MaterialFilterOptionsPy.h" using namespace Materials; /* TRANSLATOR Material::Materials */ ExternalManager* ExternalManager::_manager = nullptr; QMutex ExternalManager::_mutex; ExternalManager::ExternalManager() : _instantiated(false) { _hGrp = App::GetApplication().GetParameterGroupByPath( "User parameter:BaseApp/Preferences/Mod/Material/ExternalInterface"); _hGrp->Attach(this); getConfiguration(); } ExternalManager::~ExternalManager() { _hGrp->Detach(this); } void ExternalManager::OnChange(ParameterGrp::SubjectType& /*rCaller*/, ParameterGrp::MessageType Reason) { if (std::strncmp(Reason, "Current", 7) == 0) { if (_instantiated) { // The old manager object will be deleted when reconnecting _instantiated = false; } getConfiguration(); } } void ExternalManager::getConfiguration() { // _hGrp = App::GetApplication().GetParameterGroupByPath( // "User parameter:BaseApp/Preferences/Mod/Material/ExternalInterface"); auto current = _hGrp->GetASCII("Current", "None"); if (current == "None") { _moduleName = ""; _className = ""; } else { auto groupName = "User parameter:BaseApp/Preferences/Mod/Material/ExternalInterface/Interfaces/" + current; auto hGrp = App::GetApplication().GetParameterGroupByPath(groupName.c_str()); _moduleName = hGrp->GetASCII("Module", ""); _className = hGrp->GetASCII("Class", ""); } } void ExternalManager::instantiate() { _instantiated = false; Base::Console().log("Loading external manager…\n"); if (_moduleName.empty() || _className.empty()) { Base::Console().log("External module not defined\n"); return; } try { Base::PyGILStateLocker lock; Py::Module mod(PyImport_ImportModule(_moduleName.c_str()), true); if (mod.isNull()) { Base::Console().log(" failed\n"); return; } Py::Callable managerClass(mod.getAttr(_className)); _managerObject = managerClass.apply(); if (!_managerObject.isNull() && _managerObject.hasAttr("APIVersion")) { _instantiated = true; } if (_instantiated) { Base::Console().log("done\n"); } else { Base::Console().log("failed\n"); } } catch (Py::Exception& e) { Base::Console().log("failed\n"); e.clear(); } } void ExternalManager::connect() { if (!_instantiated) { instantiate(); if (!_instantiated) { throw ConnectionError(); } } } void ExternalManager::initManager() { QMutexLocker locker(&_mutex); if (!_manager) { _manager = new ExternalManager(); } } ExternalManager* ExternalManager::getManager() { initManager(); return _manager; } //===== // // Library management // //===== bool ExternalManager::checkMaterialLibraryType(const Py::Object& entry) { return entry.hasAttr("name") && entry.hasAttr("icon") && entry.hasAttr("readOnly"); } std::shared_ptr ExternalManager::libraryFromObject(const Py::Object& entry) { if (!checkMaterialLibraryType(entry)) { throw InvalidLibrary(); } Py::String pyName(entry.getAttr("name")); Py::Bytes pyIcon; if (entry.getAttr("icon") != Py::None()) { pyIcon = Py::Bytes(entry.getAttr("icon")); } Py::Boolean pyReadOnly(entry.getAttr("readOnly")); QString libraryName; if (!pyName.isNone()) { libraryName = QString::fromStdString(pyName.as_string()); } QByteArray icon; if (!pyIcon.isNone()) { icon = QByteArray(pyIcon.as_std_string().data(), pyIcon.size()); } bool readOnly = pyReadOnly.as_bool(); auto library = std::make_shared(libraryName, icon, readOnly); return library; } bool ExternalManager::checkMaterialLibraryObjectType(const Py::Object& entry) { return entry.hasAttr("UUID") && entry.hasAttr("path") && entry.hasAttr("name"); } LibraryObject ExternalManager::materialLibraryObjectTypeFromObject(const Py::Object& entry) { std::string uuid; auto pyUUID = entry.getAttr("UUID"); if (!pyUUID.isNone()) { uuid = pyUUID.as_string(); } std::string path; auto pyPath = entry.getAttr("path"); if (!pyPath.isNone()) { path = pyPath.as_string(); } std::string name; auto pyName = entry.getAttr("name"); if (!pyName.isNone()) { name = pyName.as_string(); } return LibraryObject(uuid, path, name); } std::shared_ptr>> ExternalManager::libraries() { auto libList = std::make_shared>>(); connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("libraries")) { Py::Callable libraries(_managerObject.getAttr("libraries")); Py::List list(libraries.apply()); for (auto lib : list) { auto library = libraryFromObject(Py::Object(lib)); libList->push_back(library); } } else { Base::Console().log("\tlibraries() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text Base::Console().log("Library error %s", e1.what()); throw LibraryNotFound(e1.what()); } return libList; } std::shared_ptr>> ExternalManager::modelLibraries() { auto libList = std::make_shared>>(); connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("modelLibraries")) { Py::Callable libraries(_managerObject.getAttr("modelLibraries")); Py::List list(libraries.apply()); for (auto lib : list) { auto library = libraryFromObject(Py::Tuple(lib)); libList->push_back(library); } } else { Base::Console().log("\tmodelLibraries() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw LibraryNotFound(e1.what()); } return libList; } std::shared_ptr>> ExternalManager::materialLibraries() { auto libList = std::make_shared>>(); connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("materialLibraries")) { Py::Callable libraries(_managerObject.getAttr("materialLibraries")); Py::List list(libraries.apply()); for (auto lib : list) { auto library = libraryFromObject(Py::Tuple(lib)); libList->push_back(library); } } else { Base::Console().log("\tmaterialLibraries() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw LibraryNotFound(e1.what()); } return libList; } std::shared_ptr ExternalManager::getLibrary(const QString& name) { // throw LibraryNotFound("Not yet implemented"); connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("getLibrary")) { Py::Callable libraries(_managerObject.getAttr("getLibrary")); Py::Tuple args(1); args.setItem(0, Py::String(name.toStdString())); Py::Object result(libraries.apply(args)); auto lib = libraryFromObject(result); return std::make_shared(*lib); } else { Base::Console().log("\tgetLibrary() not found\n"); throw ConnectionError(); } } catch (const InvalidLibrary&) { throw LibraryNotFound(); } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw LibraryNotFound(e1.what()); } } void ExternalManager::createLibrary(const QString& libraryName, const QByteArray& icon, bool readOnly) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("createLibrary")) { Py::Callable libraries(_managerObject.getAttr("createLibrary")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::Bytes(icon.data(), icon.size())); args.setItem(2, Py::Boolean(readOnly)); libraries.apply(args); // No return expected } else { Base::Console().log("\tcreateLibrary() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw CreationError(e1.what()); } } void ExternalManager::renameLibrary(const QString& libraryName, const QString& newName) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("renameLibrary")) { Py::Callable libraries(_managerObject.getAttr("renameLibrary")); Py::Tuple args(2); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(newName.toStdString())); libraries.apply(args); // No return expected } else { Base::Console().log("\trenameLibrary() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw RenameError(e1.what()); } } void ExternalManager::changeIcon(const QString& libraryName, const QByteArray& icon) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("changeIcon")) { Py::Callable libraries(_managerObject.getAttr("changeIcon")); Py::Tuple args(2); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::Bytes(icon.data(), icon.size())); libraries.apply(args); // No return expected } else { Base::Console().log("\tchangeIcon() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw ReplacementError(e1.what()); } } void ExternalManager::removeLibrary(const QString& libraryName) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("removeLibrary")) { Py::Callable libraries(_managerObject.getAttr("removeLibrary")); Py::Tuple args(1); args.setItem(0, Py::String(libraryName.toStdString())); libraries.apply(args); // No return expected } else { Base::Console().log("\tremoveLibrary() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw DeleteError(e1.what()); } } std::shared_ptr> ExternalManager::libraryModels(const QString& libraryName) { auto modelList = std::make_shared>(); connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("libraryModels")) { Py::Callable libraries(_managerObject.getAttr("libraryModels")); Py::Tuple args(1); args.setItem(0, Py::String(libraryName.toStdString())); Py::List list(libraries.apply(args)); for (auto library : list) { auto entry = Py::Object(library); if (!checkMaterialLibraryObjectType(entry)) { throw InvalidModel(); } modelList->push_back(materialLibraryObjectTypeFromObject(entry)); } } else { Base::Console().log("\tlibraryModels() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw LibraryNotFound(e1.what()); } return modelList; } std::shared_ptr> ExternalManager::libraryMaterials(const QString& libraryName) { auto materialList = std::make_shared>(); connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("libraryMaterials")) { Py::Callable libraries(_managerObject.getAttr("libraryMaterials")); Py::Tuple args(1); args.setItem(0, Py::String(libraryName.toStdString())); Py::List list(libraries.apply(args)); for (auto library : list) { auto entry = Py::Object(library); if (!checkMaterialLibraryObjectType(entry)) { throw InvalidMaterial(); } materialList->push_back(materialLibraryObjectTypeFromObject(entry)); } } else { Base::Console().log("\tlibraryMaterials() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw LibraryNotFound(e1.what()); } return materialList; } std::shared_ptr> ExternalManager::libraryMaterials(const QString& libraryName, const MaterialFilter& filter, const MaterialFilterOptions& options) { auto materialList = std::make_shared>(); connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("libraryMaterials")) { Py::Callable libraries(_managerObject.getAttr("libraryMaterials")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::Object(new MaterialFilterPy(new MaterialFilter(filter)), true)); args.setItem( 2, Py::Object(new MaterialFilterOptionsPy(new MaterialFilterOptions(options)), true)); Py::List list(libraries.apply(args)); for (auto library : list) { auto entry = Py::Object(library); if (!checkMaterialLibraryObjectType(entry)) { throw InvalidMaterial(); } materialList->push_back(materialLibraryObjectTypeFromObject(entry)); } } else { Base::Console().log("\tlibraryMaterials() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw LibraryNotFound(e1.what()); } return materialList; } std::shared_ptr> ExternalManager::libraryFolders(const QString& libraryName) { auto folderList = std::make_shared>(); connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("libraryFolders")) { Py::Callable folders(_managerObject.getAttr("libraryFolders")); Py::Tuple args(1); args.setItem(0, Py::String(libraryName.toStdString())); Py::List list(folders.apply(args)); for (auto folder : list) { auto entry = Py::Object(folder); Py::String pyName(entry.getAttr("name")); QString folderName; if (!pyName.isNone()) { folderName = QString::fromStdString(pyName.as_string()); } folderList->push_back(folderName); } } else { Base::Console().log("\tlibraryFolders() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw LibraryNotFound(e1.what()); } return folderList; } //===== // // Folder management // //===== void ExternalManager::createFolder(const QString& libraryName, const QString& path) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("createFolder")) { Py::Callable libraries(_managerObject.getAttr("createFolder")); Py::Tuple args(2); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); Py::Object result(libraries.apply(args)); } else { Base::Console().log("\tcreateFolder() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw CreationError(e1.what()); } } void ExternalManager::renameFolder(const QString& libraryName, const QString& oldPath, const QString& newPath) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("renameFolder")) { Py::Callable libraries(_managerObject.getAttr("renameFolder")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(oldPath.toStdString())); args.setItem(2, Py::String(newPath.toStdString())); Py::Object result(libraries.apply(args)); } else { Base::Console().log("\trenameFolder() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw RenameError(e1.what()); } } void ExternalManager::deleteRecursive(const QString& libraryName, const QString& path) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("deleteRecursive")) { Py::Callable libraries(_managerObject.getAttr("deleteRecursive")); Py::Tuple args(2); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); Py::Object result(libraries.apply(args)); } else { Base::Console().log("\tdeleteRecursive() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw DeleteError(e1.what()); } } //===== // // Model management // //===== bool ExternalManager::checkModelObjectType(const Py::Object& entry) { return entry.hasAttr("libraryName") && entry.hasAttr("model"); } std::shared_ptr ExternalManager::modelFromObject(const Py::Object& entry, const QString& uuid) { if (!checkModelObjectType(entry)) { throw InvalidModel(); } Py::String pyName(entry.getAttr("libraryName")); Py::Object modelObject(entry.getAttr("model")); QString libraryName; if (!pyName.isNone()) { libraryName = QString::fromStdString(pyName.as_string()); } // Using this call will use caching, whereas using our class function will not auto library = ModelManager::getManager().getLibrary(libraryName); Model* model = static_cast(*modelObject)->getModelPtr(); model->setUUID(uuid); model->setLibrary(library); auto shared = std::make_shared(*model); return shared; } std::shared_ptr ExternalManager::getModel(const QString& uuid) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("getModel")) { Py::Callable libraries(_managerObject.getAttr("getModel")); Py::Tuple args(1); args.setItem(0, Py::String(uuid.toStdString())); Py::Object result(libraries.apply(args)); // ignore return for now auto shared = modelFromObject(result, uuid); return shared; } else { Base::Console().log("\tgetModel() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw ModelNotFound(e1.what()); } } void ExternalManager::addModel(const QString& libraryName, const QString& path, const Model& model) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("addModel")) { Py::Callable libraries(_managerObject.getAttr("addModel")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); args.setItem(2, Py::Object(new ModelPy(new Model(model)), true)); libraries.apply(args); // No return expected } else { Base::Console().log("\taddModel() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw CreationError(e1.what()); } } void ExternalManager::migrateModel(const QString& libraryName, const QString& path, const Model& model) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("migrateModel")) { Py::Callable libraries(_managerObject.getAttr("migrateModel")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); args.setItem(2, Py::Object(new ModelPy(new Model(model)), true)); libraries.apply(args); // No return expected } else { Base::Console().log("\tmigrateModel() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw CreationError(e1.what()); } } void ExternalManager::updateModel(const QString& libraryName, const QString& path, const Model& model) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("updateModel")) { Py::Callable libraries(_managerObject.getAttr("updateModel")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); args.setItem(2, Py::Object(new ModelPy(new Model(model)), true)); libraries.apply(args); // No return expected } else { Base::Console().log("\tupdateModel() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw UpdateError(e1.what()); } } void ExternalManager::setModelPath(const QString& libraryName, const QString& path, const QString& uuid) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("setModelPath")) { Py::Callable libraries(_managerObject.getAttr("setModelPath")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); args.setItem(2, Py::String(uuid.toStdString())); libraries.apply(args); // No return expected } else { Base::Console().log("\tsetModelPath() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw UpdateError(e1.what()); } } void ExternalManager::renameModel(const QString& libraryName, const QString& name, const QString& uuid) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("renameModel")) { Py::Callable libraries(_managerObject.getAttr("renameModel")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(name.toStdString())); args.setItem(2, Py::String(uuid.toStdString())); libraries.apply(args); // No return expected } else { Base::Console().log("\trenameModel() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw RenameError(e1.what()); } } void ExternalManager::moveModel(const QString& libraryName, const QString& path, const QString& uuid) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("moveModel")) { Py::Callable libraries(_managerObject.getAttr("moveModel")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); args.setItem(2, Py::String(uuid.toStdString())); libraries.apply(args); // No return expected } else { Base::Console().log("\tmoveModel() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw MoveError(e1.what()); } } void ExternalManager::removeModel(const QString& uuid) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("removeModel")) { Py::Callable libraries(_managerObject.getAttr("removeModel")); Py::Tuple args(1); args.setItem(0, Py::String(uuid.toStdString())); libraries.apply(args); // No return expected } else { Base::Console().log("\tremoveModel() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw DeleteError(e1.what()); } } //===== // // Material management // //===== bool ExternalManager::checkMaterialObjectType(const Py::Object& entry) { return entry.hasAttr("libraryName") && entry.hasAttr("material"); } std::shared_ptr ExternalManager::materialFromObject(const Py::Object& entry, const QString& uuid) { if (!checkMaterialObjectType(entry)) { throw InvalidMaterial(); } Py::String pyName(entry.getAttr("libraryName")); Py::Object materialObject(entry.getAttr("material")); QString libraryName; if (!pyName.isNone()) { libraryName = QString::fromStdString(pyName.as_string()); } // Using this call will use caching, whereas using our class function will not auto library = MaterialManager::getManager().getLibrary(libraryName); Material* material = static_cast(*materialObject)->getMaterialPtr(); material->setUUID(uuid); material->setLibrary(library); auto shared = std::make_shared(*material); return shared; } std::shared_ptr ExternalManager::getMaterial(const QString& uuid) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("getMaterial")) { Py::Callable libraries(_managerObject.getAttr("getMaterial")); Py::Tuple args(1); args.setItem(0, Py::String(uuid.toStdString())); Py::Object result(libraries.apply(args)); auto shared = materialFromObject(result, uuid); return shared; } else { Base::Console().log("\tgetMaterial() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw MaterialNotFound(e1.what()); } } void ExternalManager::addMaterial(const QString& libraryName, const QString& path, const Material& material) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("addMaterial")) { Py::Callable libraries(_managerObject.getAttr("addMaterial")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); args.setItem(2, Py::Object(new MaterialPy(new Material(material)), true)); libraries.apply(args); // No return expected } else { Base::Console().log("\taddMaterial() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw CreationError(e1.what()); } } void ExternalManager::migrateMaterial(const QString& libraryName, const QString& path, const Material& material) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("migrateMaterial")) { Py::Callable libraries(_managerObject.getAttr("migrateMaterial")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); auto mat = new Material(material); args.setItem(2, Py::Object(new MaterialPy(mat), true)); libraries.apply(args); // No return expected } else { Base::Console().log("\tmigrateMaterial() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw CreationError(e1.what()); } } void ExternalManager::updateMaterial(const QString& libraryName, const QString& path, const Material& material) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("updateMaterial")) { Py::Callable libraries(_managerObject.getAttr("updateMaterial")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); args.setItem(2, Py::Object(new MaterialPy(new Material(material)), true)); libraries.apply(args); // No return expected } else { Base::Console().log("\tupdateMaterial() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw UpdateError(e1.what()); } } void ExternalManager::setMaterialPath(const QString& libraryName, const QString& path, const QString& uuid) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("setMaterialPath")) { Py::Callable libraries(_managerObject.getAttr("setMaterialPath")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); args.setItem(2, Py::String(uuid.toStdString())); libraries.apply(args); // No return expected } else { Base::Console().log("\tsetMaterialPath() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw UpdateError(e1.what()); } } void ExternalManager::renameMaterial(const QString& libraryName, const QString& name, const QString& uuid) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("renameMaterial")) { Py::Callable libraries(_managerObject.getAttr("renameMaterial")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(name.toStdString())); args.setItem(2, Py::String(uuid.toStdString())); libraries.apply(args); // No return expected } else { Base::Console().log("\trenameMaterial() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw RenameError(e1.what()); } } void ExternalManager::moveMaterial(const QString& libraryName, const QString& path, const QString& uuid) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("moveMaterial")) { Py::Callable libraries(_managerObject.getAttr("moveMaterial")); Py::Tuple args(3); args.setItem(0, Py::String(libraryName.toStdString())); args.setItem(1, Py::String(path.toStdString())); args.setItem(2, Py::String(uuid.toStdString())); libraries.apply(args); // No return expected } else { Base::Console().log("\tmoveMaterial() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw MoveError(e1.what()); } } void ExternalManager::removeMaterial(const QString& uuid) { connect(); Base::PyGILStateLocker lock; try { if (_managerObject.hasAttr("removeMaterial")) { Py::Callable libraries(_managerObject.getAttr("removeMaterial")); Py::Tuple args(1); args.setItem(0, Py::String(uuid.toStdString())); libraries.apply(args); // No return expected } else { Base::Console().log("\tremoveMaterial() not found\n"); throw ConnectionError(); } } catch (Py::Exception& e) { Base::PyException e1; // extract the Python error text throw DeleteError(e1.what()); } }