Acad::ErrorStatus ArxDbgDbEntity::wblockClone(AcRxObject* pOwner, AcDbObject*& pClone, AcDbIdMapping& idMap, Adesk::Boolean isPrimary) const { if (ArxDbgOptions::m_instance.m_showWblockCloneDetails) { CString titleStr, tmpStr; titleStr.Format(_T("Beginning -- wblockClone: %s"), ArxDbgUtils::objToClassAndHandleStr(const_cast<ArxDbgDbEntity*>(this), tmpStr)); ArxDbgUiTdmIdMap dbox(&idMap, acedGetAcadDwgView(), titleStr); dbox.DoModal(); } AcDb::DeepCloneType type = idMap.deepCloneContext(); // if xrefInsert or xrefBind, we know everything will // be cloned, so just let normal routine handle this if ((type == AcDb::kDcXrefBind) || (type == AcDb::kDcXrefInsert)) { return AcDbEntity::wblockClone(pOwner, pClone, idMap, isPrimary); } // if we've already been cloned, just return AcDbIdPair idPair(objectId(), AcDbObjectId::kNull, true); if (idMap.compute(idPair) && (idPair.value() != AcDbObjectId::kNull)) { return Acad::eOk; } // If isPrimary is kTrue, then override the default cloning // within our own cloning, which would set it to kFalse, // by cloning our referenced entity first. if (isPrimary) { // now ask derived classes what references they want cloned for them AcDbObjectIdArray refEntIds; AcDbIntArray refTypes; getCloneReferences(type, refEntIds, refTypes); ASSERT(refEntIds.length() == refTypes.length()); // clone each entity we reference first and change the value // of isPrimary to fake it out. Since we clone these first, // when the normal wblockClone is called, it will see that // they are already in the set of cloned objects and will not // try to clone it again. AcDbEntity* ent; Acad::ErrorStatus es; int len = refEntIds.length(); for (int i=0; i<len; i++) { if (refTypes[i] == kClone) { es = acdbOpenAcDbEntity(ent, refEntIds[i], AcDb::kForRead); if (es == Acad::eOk) { // this method only works if they come from the same block // (which SHOULD always be the case!) if (blockId() == ent->blockId()) { // Use the same owner, and pass in the same isPrimary value AcDbObject* pSubClone = NULL; es = ent->wblockClone(pOwner, pSubClone, idMap, Adesk::kTrue); if (pSubClone != NULL) pSubClone->close(); if (es != Acad::eOk) { ASSERT(0); } } else { ASSERT(0); } ent->close(); } } } } // Now we can clone ourselves via calling our parent's method. Acad::ErrorStatus es = AcDbEntity::wblockClone(pOwner, pClone, idMap, isPrimary); if (ArxDbgOptions::m_instance.m_showWblockCloneDetails) { CString titleStr, tmpStr; titleStr.Format(_T("End -- wblockClone: %s"), ArxDbgUtils::objToClassAndHandleStr(const_cast<ArxDbgDbEntity*>(this), tmpStr)); ArxDbgUiTdmIdMap dbox(&idMap, acedGetAcadDwgView(), titleStr); dbox.DoModal(); } return es; }
Acad::ErrorStatus ArxDbgUtils::verifyEntityReference(const AcDbEntity* ent, const AcDbObjectId& idToValidate, AcRxClass* classType, bool allowNull, bool allowErased) { if (ent == NULL) { ASSERT(0); return Acad::eInvalidInput; } // first check for NULL if (idToValidate == AcDbObjectId::kNull) { if (allowNull) return Acad::eOk; else return Acad::eNullObjectId; } // now open it up and see what it is Acad::ErrorStatus es; AcDbEntity* entToValidate; es = acdbOpenAcDbEntity(entToValidate, idToValidate, AcDb::kForRead); if (es == Acad::eOk) { // make sure all references are from the same database // which should always be the case! if (ent->database() != entToValidate->database()) { entToValidate->close(); return Acad::eWrongDatabase; } // make sure that references are from the same block // This can fail from a simple deepClone() to make a // blockTableRecord. If the user didn't pick all the // referenced objects in the anchor at the time of // making the block, they will still point to the // entities in modelSpace... which will eventually crash // the whole thing. if (ent->blockId() != entToValidate->blockId()) { entToValidate->close(); return Acad::eNotInBlock; } // see if they want to validate based on object type if (classType != NULL) { es = verifyClassType(entToValidate, classType); if (es != Acad::eOk) { entToValidate->close(); return es; } } entToValidate->close(); return Acad::eOk; // passed our test } else if (es == Acad::eWasErased) { if (allowErased) return Acad::eOk; // passed under relaxed constraints else return Acad::eWasErased; // failed } else { return es; // failed } }