/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, 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 Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 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 "DbNamedObjectIndex.h" #include "StaticRxObject.h" #include "DbAssocVariable.h" #include "DbAssocNetwork.h" ODRX_NO_CONS_DEFINE_MEMBERS( OdDbNamedObjectPE, OdRxObject ) ODRX_NO_CONS_DEFINE_MEMBERS( OdDbNamedObjectIndex, OdDbObjectReactor ) ODRX_NO_CONS_DEFINE_MEMBERS( OdDbNamedObjectIndexNode, OdDbObjectReactor ) OdDbNamedObjectIndexNode::OdDbNamedObjectIndexNode() : m_index(nullptr) , m_prev(nullptr) , m_next(nullptr) , m_flags(kDirty) { } void OdDbNamedObjectIndexNode::initInIndex(const OdDbObject* object, OdDbNamedObjectIndex* index) { SETBIT(m_flags, kModified, object->isModified()); SETBIT(m_flags, kOpenedForModify, (isModified() && object->isWriteEnabled())); SETBIT(m_flags, kDirty, isModified() || isOpenedForModify()); m_index = index; m_id = object->objectId(); if(!isDirty()) { OdDbNamedObjectPEPtr px(object); ODA_VERIFY(px->getObjectName(object, m_name)==eOk); if (!m_name.isEmpty()) { m_name.makeLower(); index->nodesByName.insert(this); } } index->addToList(this); } OdDbNamedObjectIndexNode* OdDbNamedObjectIndexNode::fromObject(const OdDbObject* object, OdDbNamedObjectIndex* createInIndex /*= nullptr*/) { if(!object || createInIndex && !object->isKindOf(createInIndex->classIndexed)) return nullptr; OdDbNamedObjectIndexNode* node = static_cast( OdDbObjectReactor::findReactor(object, OdDbNamedObjectIndexNode::desc()) ); if(node && createInIndex) { OdDbNamedObjectIndex* oldIndex = node->m_index; if(oldIndex!=createInIndex) { node->removeFromIndex(); node->initInIndex(object, createInIndex); return node; } } if(!node && createInIndex) { object->addReactor(node = new OdStaticRxObject); node->initInIndex(object, createInIndex); } return node; } void OdDbNamedObjectIndexNode::openedForModify(const OdDbObject* object) { (void)object; ODA_ASSERT(!isOpenedForModify() || object->isNewObject()); SETBIT_1(m_flags, kOpenedForModify|kModified); if(m_index) { if(!isDirty()) { m_index->removeFromList(this); // from upToDate list SETBIT_1(m_flags, kDirty); m_index->addToList(this); // to dirty list } } else { m_name.empty(); } } void OdDbNamedObjectIndexNode::erased(const OdDbObject* pObject, bool erasing /*= true*/) { if(erasing) goodbye(pObject); } void OdDbNamedObjectIndexNode::modified(const OdDbObject* /*object*/) { ODA_ASSERT(isOpenedForModify()); SETBIT_0(m_flags, kOpenedForModify); } void OdDbNamedObjectIndexNode::goodbye(const OdDbObject* object) { removeFromIndex(); object->removeReactor(this); delete this; } bool OdDbNamedObjectIndexNode::update() { if(isModified()) { OdDbObjectPtr object = m_id.openObject(); if(object.get()) return update(object); } return false; } bool OdDbNamedObjectIndexNode::update(const OdDbObject* object) { OdDbNamedObjectPEPtr px(object); OdString newName; ODA_VERIFY(px->getObjectName(object, newName)==eOk); newName.makeLower(); m_id = object->objectId(); // it's exotic case but id may be changed, so update it also if(newName != m_name) { if(m_index) m_index->nodesByName.erase(this); m_name = newName; return true; } return false; } OdDbNamedObjectIndex::OdDbNamedObjectIndex() : numUpToDate(0) , upToDateNodes(nullptr) , numDirty(0) , dirtyNodes(nullptr) , bNeedRegen(true) { } void OdDbNamedObjectIndex::update() { if(needRegen()) { OdDbAssocNetworkPtr network = indexHolderId.safeOpenObject(); OdDbObjectIdArray objects = network->getActions(); reset(); for(unsigned int i = 0, n = objects.length(); i < n; ++i) { OdDbObjectId id = objects[i]; if(!id.objectClass()->isDerivedFrom(classIndexed)) continue; OdDbObjectPtr object = id.openObject(OdDb::kForRead, true); if(object.get()) OdDbNamedObjectIndexNode::fromObject(object, this); } } OdDbNamedObjectIndexNode* node = dirtyNodes; if(node) { OdLinkedArray> renamed; do { OdDbNamedObjectIndexNode* next = node->m_next; if(node->update()) renamed.append(node); if(!node->isOpenedForModify()) { removeFromList(node); // from dirty SETBIT_0(node->m_flags, OdDbNamedObjectIndexNode::kDirty); addToList(node); // to up-to-date } node = next; } while(node); while (renamed.size()) { if (!renamed.last()->m_name.isEmpty()) nodesByName.insert(renamed.last()); renamed.removeLast(); } } bNeedRegen = false; } void OdDbNamedObjectIndexNode::removeFromIndex() { if(m_index) { if(!m_name.isEmpty()) m_index->nodesByName.erase(this); m_index->removeFromList(this); m_index = nullptr; } } void OdDbNamedObjectIndex::addToList(OdDbNamedObjectIndexNode* node) { ODA_ASSERT(node->m_next==nullptr && node->m_prev==nullptr); if(node->isDirty()) { if(dirtyNodes) { node->m_next = dirtyNodes; dirtyNodes->m_prev = node; } dirtyNodes = node; ++numDirty; } else { if(upToDateNodes) { node->m_next = upToDateNodes; upToDateNodes->m_prev = node; } upToDateNodes = node; ++numUpToDate; } } void OdDbNamedObjectIndex::removeFromList(OdDbNamedObjectIndexNode* node) { if(node->m_prev) { node->m_prev->m_next = node->m_next; if(node->isDirty()) --numDirty; else --numUpToDate; } else if(node->isDirty()) { dirtyNodes = node->m_next; --numDirty; } else { upToDateNodes = node->m_next; --numUpToDate; } if(node->m_next) { node->m_next->m_prev = node->m_prev; node->m_next = nullptr; } node->m_prev = nullptr; } OdDbNamedObjectIndex* OdDbNamedObjectIndex::fromObject(const OdDbObject* net, const OdRxClass* classToBeIndexed, bool create) { if(!net) return nullptr; OdDbNamedObjectIndex* index = static_cast( OdDbObjectReactor::findReactor(net, OdDbNamedObjectIndex::desc()) ); if(!index && create) { if(!net->isKindOf(OdDbAssocNetwork::desc())) // only OdDbAssocNetwork is currently supported as index holder return nullptr; net->addReactor(index = new OdStaticRxObject); index->indexHolderId = net->objectId(); index->classIndexed = classToBeIndexed; } return index; } OdDbObjectId OdDbNamedObjectIndex::objectByName(const OdString& name) { update(); OdStaticRxObject key; key.m_name = name; key.m_name.makeLower(); NodesByName::const_iterator it = nodesByName.find(&key); if(it == nodesByName.end()) return OdDbObjectId::kNull; return (*it)->m_id; } void OdDbNamedObjectIndex::goodbye(const OdDbObject* pObject) { reset(); pObject->removeReactor(this); delete this; } void OdDbNamedObjectIndex::reset() { nodesByName.clear(); while(dirtyNodes) dirtyNodes->removeFromIndex(); while(upToDateNodes) upToDateNodes->removeFromIndex(); }