/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2018, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Teigha(R) software pursuant to a license // agreement with Open Design Alliance. // Teigha(R) Copyright (C) 2002-2018 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "RxModelHierarchyTreeBase.h" #include "RxValue.h" #include "RxValueTypeUtil.h" #include "RxMember.h" #include "RxObjectImpl.h" #include "RxAttribute.h" #include "RxSysRegistry.h" #include "RxModelHierarchyTreeBaseImpl.h" #include "RxProperty.h" #include "RxModelTreeBaseNodeImpl.h" ODRX_CONS_DEFINE_MEMBERS(OdRxModelHierarchyTreeBase, OdRxObject, RXIMPL_CONSTR) #define _GET_IMPL_ \ \ OdRxModelHierarchyTreeBaseImpl* pImpl = OdRxModelHierarchyTreeBaseImpl::getImpl(this); \ if (NULL == pImpl)\ { \ throw OdError(::eNullObjectPointer); \ } class OdRxModelHierarchyTreeImpl : public OdRxModelHierarchyTreeBaseImpl { public: OdRxModelHierarchyTreeImpl() : OdRxModelHierarchyTreeBaseImpl() { } OdRxModelTreeBaseNodePtr createNodeObject() { return OdRxModelTreeBaseNode::createObject(); } }; OdRxModelHierarchyTreeBase::OdRxModelHierarchyTreeBase() :m_pImpl(new OdRxModelHierarchyTreeImpl) { } OdRxModelHierarchyTreeBase::OdRxModelHierarchyTreeBase(OdRxModelHierarchyTreeBaseImpl* impl) :m_pImpl(impl) { } OdRxModelHierarchyTreeBase::~OdRxModelHierarchyTreeBase() { delete m_pImpl; } OdRxModelTreeBaseNodePtr OdRxModelHierarchyTreeBase::createDatabaseHierarchyTree(const OdRxObject* pDb, const bool create_properties_cache /*= true*/) { _GET_IMPL_ return pImpl->createDatabaseHierarchyTree(pDb, create_properties_cache); } OdRxModelTreeBaseNodePtr OdRxModelHierarchyTreeBase::getDatabaseNode() const { _GET_IMPL_ return pImpl->getDatabaseNode(); } OdArray OdRxModelHierarchyTreeBase::getNodeProperties(OdUInt64 unique_source_ID) { _GET_IMPL_ return pImpl->getNodeProperties(unique_source_ID); } void OdRxModelHierarchyTreeBase::serialize(OdBaseHierarchyTreeFiler* pFiler) const { _GET_IMPL_ return pImpl->serialize(pFiler); } OdResult OdRxModelHierarchyTreeBase::deserialize(OdBaseHierarchyTreeFiler* pFiler) { _GET_IMPL_ return pImpl->deserialize(pFiler); } OdRxModelHierarchyTreeBaseImpl::OdRxModelHierarchyTreeBaseImpl() { } OdRxModelHierarchyTreeBaseImpl::~OdRxModelHierarchyTreeBaseImpl() { } OdRxModelTreeBaseNodePtr OdRxModelHierarchyTreeBaseImpl::getDatabaseNode() const { return m_DatabaseNode; } OdRxModelTreeBaseNodePtr OdRxModelHierarchyTreeBaseImpl::createDatabaseHierarchyTree(const OdRxObject* pDb, const bool create_properties_cache /*= true*/) { m_DatabaseNode = createNodeObject(); m_NodeCache.clear(); processNode(m_DatabaseNode, pDb, m_NodeCache, create_properties_cache); if (m_DatabaseNode->getNodeName().isEmpty()) { OdRxModelTreeBaseNodeImpl* pImpl = OdRxModelTreeBaseNodeImpl::getImpl(m_DatabaseNode); OdRxPropertyPtr pFileNameProp = OdRxMemberQueryEngine::theEngine()->find(pDb, L"FileName"); if (!pFileNameProp.isNull()) { OdRxValue valFileName; if (eOk == pFileNameProp->getValue(pDb, valFileName)) { OdString file_path = *rxvalue_cast(&valFileName); int i1 = file_path.reverseFind('\\'); int i2 = file_path.reverseFind('/'); int i = odmax(i1, i2); file_path = file_path.mid(i + 1); i = file_path.find(L'.'); if (i != -1) file_path = file_path.left(i); pImpl->setNodeName(file_path); } } if (m_DatabaseNode->getNodeName().isEmpty()) { pImpl->setNodeName(L"Database"); } } return m_DatabaseNode; } void OdRxModelHierarchyTreeBaseImpl::processElement(OdRxModelTreeBaseNode* pParent, AttributesInfo& attributes_info, OdRxValue& prop_value, std::map& cache, const bool create_properties_cache) { OdRxObjectPtr pChildObj; if (prop_value.type().isReference()) { const IOdRxReferenceType* pRef = prop_value.type().reference(); if (NULL == pRef) return; pChildObj = pRef->dereference(prop_value, IOdRxReferenceType::kForRead); } else { const IOdRxObjectValue* pValue = prop_value.type().rxObjectValue(); if (NULL == pValue) return; pChildObj = pValue->getRxObject(prop_value); } if (NULL == pChildObj) return; bool is_unic_found(false); OdUInt64 uinic_ID(0); OdRxPropertyPtr pHandleProp = OdRxMemberQueryEngine::theEngine()->find(pChildObj, L"ODAUniqueID"); if (!pHandleProp.isNull()) { OdRxValue valHandle; if (eOk == pHandleProp->getValue(pChildObj, valHandle)) { is_unic_found = true; uinic_ID = *rxvalue_cast(&valHandle); } } OdRxModelTreeBaseNodePtr pChild; if (is_unic_found) { std::map::const_iterator iter = cache.find(uinic_ID); if (cache.end() != iter) pChild = iter->second; } if (pChild.isNull()) { pChild = createNodeObject(); cache[uinic_ID] = pChild; OdRxModelTreeBaseNodeImpl* pImpl = OdRxModelTreeBaseNodeImpl::getImpl(pChild); if (NULL != attributes_info.pNameAttribute) pImpl->setNodeName(attributes_info.pNameAttribute->getDisplayValue(prop_value)); OdString hierarchy_value = attributes_info.pHierarchyAttribute->value(prop_value); if (0 == OdString(L"Model").compare(hierarchy_value)) { pImpl->setNodeType(eModel); } else { if (0 == OdString(L"BlockReference").compare(hierarchy_value)) { pImpl->setNodeType(eBlockReference); } else { if (0 == OdString(L"Block").compare(hierarchy_value)) { pImpl->setNodeType(eBlock); } else { if (0 == OdString(L"Hidden").compare(hierarchy_value)) { pImpl->setNodeType(eHidden); } else pImpl->setNodeType(eEntity); } } } if (pImpl->getNodeName().isEmpty()) { if (hierarchy_value.isEmpty()) pImpl->setNodeName(L"Entity"); else pImpl->setNodeName(hierarchy_value); } if (is_unic_found) { pImpl->setUniqueSourceID(uinic_ID); } processNode(pChild, pChildObj, cache, create_properties_cache); } pParent->addChild(pChild); } struct SinglePropertyFunctor { template static bool processValue(OdRxPropertyVariant& variant, const OdRxValue& value) { const ValueType* val = rxvalue_cast(&value); if (val == 0) return false; variant = *val; return true; } static bool processDefaultValue(OdRxPropertyVariant& variant, const OdString& value) { variant = value; return true; } }; template static bool compareValueType(const OdRxValueType& valueType) { OdRxValueType::Desc valueStruct = OdRxValueType::Desc(); return valueType == valueStruct.value(); } template bool processPropertyValue(OdRxPropertyVariant& variant, const OdRxValue& value) { if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else if (compareValueType(value.type())) { return FunctorType::template processValue(variant, value); } else { FunctorType::processDefaultValue(variant, value.toString()); return true; } } void OdRxModelHierarchyTreeBaseImpl::processRxProperty(OdRxModelTreeBaseNode* pParent, const OdRxObject* pObj, OdRxProperty* pProperty, PropertyInfo& info, AttributesInfo& attributes_info, std::map& cache, const bool create_properties_cache) { try { OdRxValue prop_value; if (eOk == pProperty->getValue(pObj, prop_value)) { if (create_properties_cache && !prop_value.isEmpty()) { info.name = pProperty->name(); if (NULL == attributes_info.pLocalizedNameAttribute) { info.localizedName = pProperty->localName(); } else { info.localizedName = attributes_info.pLocalizedNameAttribute->getLocalizedName(pProperty); } if (NULL == attributes_info.pUiPlacementAttribute) { info.weight = 0.; } else { info.weight = attributes_info.pUiPlacementAttribute->getWeight(pProperty); info.uiPlacement = attributes_info.pUiPlacementAttribute->getCategory(pProperty); } processPropertyValue(info.value, prop_value); } if (NULL != attributes_info.pHierarchyAttribute) { processElement(pParent, attributes_info, prop_value, cache, create_properties_cache); } } } catch (...) { } } struct CollectionInitPropertyFunctor { template static bool processValue(OdRxPropertyVariant& variant, const OdRxValue& value) { return false; } static bool processDefaultValue(OdRxPropertyVariant& variant, const OdString& value) { OdStringArray array; variant.setStringArray(array); return true; } }; #undef TYPE_CONTAINER #define TYPE_CONTAINER \ VARTYPE(String )\ VARTYPE(Bool )\ VARTYPE(Int8 )\ VARTYPE(Int16 )\ VARTYPE(Int32 )\ VARTYPE(Int64 )\ VARTYPE(UInt8 )\ VARTYPE(UInt16 )\ VARTYPE(UInt32 )\ VARTYPE(UInt64 )\ VARTYPE(Double )\ VARTYPE(GePoint2d )\ VARTYPE(GePoint3d )\ VARTYPE(GeVector2d )\ VARTYPE(GeVector3d )\ VARTYPE(CmEntityColor )\ VARTYPE(CmTransparency ) #define ODTYPE(Type) Od##Type #undef VARTYPE #define VARTYPE(Type) \ template <>\ bool CollectionInitPropertyFunctor::processValue(OdRxPropertyVariant& variant, const OdRxValue& value)\ {\ Od##Type##Array array;\ variant.set##Type##Array(array);\ return true;\ } TYPE_CONTAINER struct CollectionPropertyFunctor { template static bool processValue(OdRxPropertyVariant& variant, const OdRxValue& value) { return false; } static bool processDefaultValue(OdRxPropertyVariant& variant, const OdString& value) { if (OdRxPropertyVariant::kString == variant.varType()) variant.asStringArray().append(value); return true; } }; #undef TYPE_CONTAINER #define TYPE_CONTAINER \ VARTYPE(String )\ VARTYPE(Bool )\ VARTYPE(Int8 )\ VARTYPE(Int16 )\ VARTYPE(Int32 )\ VARTYPE(Int64 )\ VARTYPE(UInt8 )\ VARTYPE(UInt16 )\ VARTYPE(UInt32 )\ VARTYPE(UInt64 )\ VARTYPE(Double )\ VARTYPE(GePoint2d )\ VARTYPE(GePoint3d )\ VARTYPE(GeVector2d )\ VARTYPE(GeVector3d )\ VARTYPE(CmEntityColor )\ VARTYPE(CmTransparency ) #define ODTYPE(Type) Od##Type #undef VARTYPE #define VARTYPE(Type) \ template <>\ bool CollectionPropertyFunctor::processValue(OdRxPropertyVariant& variant, const OdRxValue& value)\ {\ const ODTYPE(Type)* val = rxvalue_cast(&value);\ if (val != 0 && OdRxPropertyVariant::k##Type == variant.type())\ variant.as##Type##Array().append(*val);\ return true;\ } TYPE_CONTAINER void OdRxModelHierarchyTreeBaseImpl::processRxCollection(OdRxModelTreeBaseNode* pParent, const OdRxObject* pObj, const OdRxCollectionProperty* pPropertyCollection, PropertyInfo& info, AttributesInfo& attributes_info, std::map& cache, const bool create_properties_cache) { OdRxValueIteratorPtr pPrIt = pPropertyCollection->newValueIterator(pObj); if (!pPrIt.isNull()) { if (pPrIt->done()) return; OdRxValue initial_prop_value = pPrIt->current(); if (create_properties_cache) { info.name = pPropertyCollection->name(); if (NULL == attributes_info.pLocalizedNameAttribute) { info.localizedName = pPropertyCollection->localName(); } else { info.localizedName = attributes_info.pLocalizedNameAttribute->getLocalizedName(pPropertyCollection); } if (NULL == attributes_info.pUiPlacementAttribute) { info.weight = 0.; } else { info.weight = attributes_info.pUiPlacementAttribute->getWeight(pPropertyCollection); info.uiPlacement = attributes_info.pUiPlacementAttribute->getCategory(pPropertyCollection); } processPropertyValue(info.value, initial_prop_value); } while (!pPrIt->done()) { OdRxValue prop_value = pPrIt->current(); if (create_properties_cache) { processPropertyValue(info.value, prop_value); } if (NULL != attributes_info.pHierarchyAttribute) { processElement(pParent, attributes_info, prop_value, cache, create_properties_cache); } pPrIt->next(); } } } void OdRxModelHierarchyTreeBaseImpl::processNode(OdRxModelTreeBaseNode* pParent, const OdRxObject* pObj, std::map& cache, const bool create_properties_cache) { OdRxMemberIteratorPtr it = OdRxMemberQueryEngine::theEngine()->newMemberIterator(pObj); while (!it->done()) { PropertyInfo info; processProperty(pParent, pObj, it->current(), info, cache, create_properties_cache); if (create_properties_cache) { OdRxModelTreeBaseNodeImpl::getImpl(pParent)->addProperty(info); } it->next(); } } void OdRxModelHierarchyTreeBaseImpl::processProperty(OdRxModelTreeBaseNode* pParent, const OdRxObject* pObj, const OdRxMember* pRxMember, PropertyInfo& info, std::map& cache, const bool create_properties_cache) { if (NULL != pRxMember && NULL != pRxMember->isA()) { AttributesInfo attributes_info; const OdRxAttributeCollection& attributes = pRxMember->attributes(); for (int i = 0; i < attributes.count(); i++) { const OdRxAttribute* pAttribute = attributes.getAt(i); if (NULL != pAttribute->isA() && pAttribute->isKindOf(OdRxHierarchyLevelAttribute::desc())) { attributes_info.pHierarchyAttribute = (OdRxHierarchyLevelAttribute*)pAttribute; } if (NULL != pAttribute->isA() && pAttribute->isKindOf(OdRxDisplayAsAttribute::desc())) { attributes_info.pNameAttribute = (OdRxDisplayAsAttribute*)pAttribute; } if (NULL != pAttribute->isA() && pAttribute->isKindOf(OdRxUiPlacementAttribute::desc())) { attributes_info.pUiPlacementAttribute = (OdRxUiPlacementAttribute*)pAttribute; } if (NULL != pAttribute->isA() && pAttribute->isKindOf(OdRxLocalizedNameAttribute::desc())) { attributes_info.pLocalizedNameAttribute = (OdRxLocalizedNameAttribute*)pAttribute; } } if (!create_properties_cache && !attributes_info.pHierarchyAttribute) return; const bool is_property = pRxMember->isA()->isDerivedFrom(OdRxProperty::desc()); const bool is_collection = pRxMember->isA()->isDerivedFrom(OdRxCollectionProperty::desc()); if (is_property) { processRxProperty(pParent, pObj, (OdRxProperty*)pRxMember, info, attributes_info, cache, create_properties_cache); } if (is_collection) { processRxCollection(pParent, pObj, (OdRxCollectionProperty*)pRxMember, info, attributes_info, cache, create_properties_cache); } if (is_property || is_collection) { if (const OdArray* pChildern = pRxMember->children()) { const OdArray::size_type length = pChildern->length(); info.subProperties.resize(length); for (OdArray::size_type i = 0; i < length; ++i) { processProperty(pParent, pObj, pChildern->getAt(i).get(), info.subProperties[i], cache, create_properties_cache); } } } } } void OdRxModelHierarchyTreeBaseImpl::serialize(OdBaseHierarchyTreeFiler* pFiler) const { OdArray cache; createNodeCache(m_DatabaseNode, cache); pFiler->wrUInt8((OdUInt8)eCURRENT); pFiler->wrInt64(cache.size()); for (OdArray::const_iterator elem_it = cache.begin(); elem_it != cache.end(); ++elem_it) { elem_it->m_pNode->outFields(pFiler); pFiler->wrInt64(elem_it->m_IDs.size()); for (OdArray::const_iterator ids_it = elem_it->m_IDs.begin(); ids_it != elem_it->m_IDs.end(); ++ids_it) { pFiler->wrInt64(*ids_it); } } } OdResult OdRxModelHierarchyTreeBaseImpl::deserialize(OdBaseHierarchyTreeFiler* pFiler) { m_NodeCache.clear(); HierarchyTreeVersion version = (HierarchyTreeVersion)pFiler->rdUInt8(); OdUInt64 node_count = pFiler->rdInt64(); OdArray cache(node_count); cache.resize(node_count); for (OdUInt64 node_num = 0; node_num < node_count; ++node_num) { cache[node_num] = createNodeObject(); cache[node_num]->inFields(pFiler); OdUInt64 children_count = pFiler->rdInt64(); for (OdUInt64 ch_num = 0; ch_num < children_count; ++ch_num) { OdUInt64 ch_index = pFiler->rdInt64(); cache[node_num]->addChild(cache[ch_index]); } m_NodeCache[cache[node_num]->getUniqueSourceID()] = cache[node_num]; } m_DatabaseNode = cache[node_count - 1]; return eOk; } OdUInt64 OdRxModelHierarchyTreeBaseImpl::createNodeCache(OdRxModelTreeBaseNodePtr pNode, OdArray& cache) const { NodeCache elem; const OdRxModelTreeBaseNodePtrArray children = pNode->getChildren(); const OdRxModelTreeBaseNodePtrArray::size_type children_count = children.size(); for (OdRxModelTreeBaseNodePtrArray::size_type i = 0; i < children_count; ++i) { elem.m_IDs.append(createNodeCache(children[i], cache)); } elem.m_pNode = pNode; return cache.append(elem); } OdArray OdRxModelHierarchyTreeBaseImpl::getNodeProperties(OdUInt64 unique_source_ID) { std::map::const_iterator it = m_NodeCache.find(unique_source_ID); if (m_NodeCache.end() == it) return OdArray(); return it->second->getProperties(); }