/*************************************************************************** * Copyright (c) 2015 Alexander Golubev (Fat-Zer) * * * * 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 "OriginGroupExtension.h" #include "GeoFeature.h" #include "Origin.h" FC_LOG_LEVEL_INIT("App", true, true) using namespace App; EXTENSION_PROPERTY_SOURCE(App::OriginGroupExtension, App::GeoFeatureGroupExtension) OriginGroupExtension::OriginGroupExtension() { initExtensionType(OriginGroupExtension::getExtensionClassTypeId()); EXTENSION_ADD_PROPERTY_TYPE(Origin, (nullptr), 0, App::Prop_Hidden, "Origin linked to the group"); Origin.setScope(LinkScope::Child); } OriginGroupExtension::~OriginGroupExtension() = default; App::Origin* OriginGroupExtension::getOrigin() const { App::DocumentObject* originObj = Origin.getValue(); if (!originObj) { std::stringstream err; err << "Can't find Origin for \"" << getExtendedObject()->getFullName() << "\""; throw Base::RuntimeError(err.str().c_str()); } else if (!originObj->isDerivedFrom()) { std::stringstream err; err << "Bad object \"" << originObj->getFullName() << "\"(" << originObj->getTypeId().getName() << ") linked to the Origin of \"" << getExtendedObject()->getFullName() << "\""; throw Base::RuntimeError(err.str().c_str()); } else { return static_cast(originObj); } } bool OriginGroupExtension::extensionGetSubObject(DocumentObject*& ret, const char* subname, PyObject** pyObj, Base::Matrix4D* mat, bool transform, int depth) const { App::DocumentObject* originObj = Origin.getValue(); const char* dot; if (originObj && originObj->isAttachedToDocument() && subname && (dot = strchr(subname, '.'))) { bool found; if (subname[0] == '$') { found = std::string(subname + 1, dot) == originObj->Label.getValue(); } else { found = std::string(subname, dot) == originObj->getNameInDocument(); } if (found) { if (mat && transform) { *mat *= const_cast(this)->placement().getValue().toMatrix(); } ret = originObj->getSubObject(dot + 1, pyObj, mat, true, depth + 1); return true; } } return GeoFeatureGroupExtension::extensionGetSubObject(ret, subname, pyObj, mat, transform, depth); } App::DocumentObject* OriginGroupExtension::getGroupOfObject(const DocumentObject* obj) { if (!obj) { return nullptr; } bool isOriginFeature = obj->isDerivedFrom(); auto list = obj->getInList(); for (auto o : list) { if (o->hasExtension(App::OriginGroupExtension::getExtensionClassTypeId())) { return o; } else if (isOriginFeature && o->isDerivedFrom()) { auto result = getGroupOfObject(o); if (result) { return result; } } } return nullptr; } short OriginGroupExtension::extensionMustExecute() { if (Origin.isTouched()) { return 1; } else { return GeoFeatureGroupExtension::extensionMustExecute(); } } App::DocumentObjectExecReturn* OriginGroupExtension::extensionExecute() { try { // try to find all base axis and planes in the origin getOrigin(); } catch (const Base::Exception& ex) { // getExtendedObject()->setError (); return new App::DocumentObjectExecReturn(ex.what()); } return GeoFeatureGroupExtension::extensionExecute(); } App::DocumentObject* OriginGroupExtension::getLocalizedOrigin(App::Document* doc) { auto* originObject = doc->addObject("Origin"); QByteArray byteArray = tr("Origin").toUtf8(); originObject->Label.setValue(byteArray.constData()); return originObject; } void OriginGroupExtension::onExtendedSetupObject() { App::Document* doc = getExtendedObject()->getDocument(); App::DocumentObject* originObj = getLocalizedOrigin(doc); assert(originObj && originObj->isDerivedFrom()); Origin.setValue(originObj); GeoFeatureGroupExtension::onExtendedSetupObject(); } void OriginGroupExtension::onExtendedUnsetupObject() { App::DocumentObject* origin = Origin.getValue(); if (origin && !origin->isRemoving()) { origin->getDocument()->removeObject(origin->getNameInDocument()); } GeoFeatureGroupExtension::onExtendedUnsetupObject(); } void OriginGroupExtension::extensionOnChanged(const Property* p) { if (p == &Origin) { App::DocumentObject* owner = getExtendedObject(); App::DocumentObject* origin = Origin.getValue(); // Document::Importing indicates the object is being imported (i.e. // copied). So check the Origin ownership here to prevent copy without // dependency if (origin && owner && owner->getDocument() && owner->getDocument()->testStatus(Document::Importing)) { for (auto o : origin->getInList()) { if (o != owner && o->hasExtension(App::OriginGroupExtension::getExtensionClassTypeId())) { App::Document* document = owner->getDocument(); // Temporarily reset 'Restoring' status to allow document to auto label new // objects Base::ObjectStatusLocker guard(Document::Restoring, document, false); Origin.setValue(getLocalizedOrigin(document)); FC_WARN("Reset origin in " << owner->getFullName()); return; } } } } GeoFeatureGroupExtension::extensionOnChanged(p); } void OriginGroupExtension::relinkToOrigin(App::DocumentObject* obj) { // we get all links and replace the origin objects if needed (subnames need not to change, they // would stay the same) std::vector result; std::vector list; obj->getPropertyList(list); auto isOriginFeature = [](App::DocumentObject* obj) -> bool { // Check if the object is a DatumElement if (auto* datumElement = dynamic_cast(obj)) { // Check if the DatumElement is an origin return datumElement->isOriginFeature(); } return false; }; for (App::Property* prop : list) { if (prop->isDerivedFrom()) { auto p = static_cast(prop); if (!p->getValue() || !isOriginFeature(p->getValue())) { continue; } p->setValue(getOrigin()->getDatumElement( static_cast(p->getValue())->Role.getValue())); } else if (prop->isDerivedFrom()) { auto p = static_cast(prop); auto vec = p->getValues(); std::vector result; bool changed = false; for (App::DocumentObject* o : vec) { if (!isOriginFeature(o)) { result.push_back(o); } else { result.push_back(getOrigin()->getDatumElement( static_cast(o)->Role.getValue())); changed = true; } } if (changed) { static_cast(prop)->setValues(result); } } else if (prop->isDerivedFrom()) { auto p = static_cast(prop); if (!p->getValue() || !isOriginFeature(p->getValue())) { continue; } std::vector subValues = p->getSubValues(); p->setValue(getOrigin()->getDatumElement( static_cast(p->getValue())->Role.getValue()), subValues); } else if (prop->isDerivedFrom()) { auto p = static_cast(prop); auto vec = p->getSubListValues(); bool changed = false; for (auto& v : vec) { if (isOriginFeature(v.first)) { v.first = getOrigin()->getDatumElement( static_cast(v.first)->Role.getValue()); changed = true; } } if (changed) { p->setSubListValues(vec); } } } } std::vector OriginGroupExtension::addObjects(std::vector objs) { for (auto obj : objs) { relinkToOrigin(obj); } return App::GeoFeatureGroupExtension::addObjects(objs); } bool OriginGroupExtension::hasObject(const DocumentObject* obj, bool recursive) const { if (Origin.getValue() && (obj == getOrigin() || getOrigin()->hasObject(obj))) { return true; } return App::GroupExtension::hasObject(obj, recursive); } // Python feature --------------------------------------------------------- namespace App { EXTENSION_PROPERTY_SOURCE_TEMPLATE(App::OriginGroupExtensionPython, App::OriginGroupExtension) // explicit template instantiation template class AppExport ExtensionPythonT>; } // namespace App