// AsdkNODEdReactor is derived from AcEditorReactor // void AsdkNODEdReactor::beginDeepCloneXlation( AcDbIdMapping& idMap, Acad::ErrorStatus* pRetStat) { Acad::ErrorStatus es; AcDbObjectId dictId; if ( idMap.deepCloneContext() != AcDb::kDcWblock && idMap.deepCloneContext() != AcDb::kDcInsert) return; // Get the "from" and "to" databases. // AcDbDatabase *pFrom, *pTo; idMap.origDb(pFrom); idMap.destDb(pTo); // See if the "from" database has our dictionary, and // open it. If it doesn't have one, we are done. // AcDbDictionary *pSrcNamedObjDict; pFrom->getNamedObjectsDictionary(pSrcNamedObjDict, AcDb::kForRead); es = pSrcNamedObjDict->getAt(kpDictionary, dictId); pSrcNamedObjDict->close(); if (es == Acad::eKeyNotFound) return; AcDbDictionary *pSrcDict; acdbOpenObject(pSrcDict, dictId, AcDb::kForRead); AcDbObject *pClone; switch (idMap.deepCloneContext()) { case AcDb::kDcWblock: // WBLOCK clones all, or part of a drawing into a // newly created drawing. This means that the // NamedObject Dictionary is always cloned, and // its AcDbObjectIds are in flux. Therefore, you // cannot use getAt() or setAt() on the dictionary // in the new database. This is because the // cloned dictionary references all refer to the // original objects. During Deep Clone translation, // all cloned entries will be translated to the // new objects, and entries not cloned will be // "removed" by getting "translated" to NULL. // // The cloning of entries in our own dictionary are // not handled here. If all are to be cloned, then // call setTreatElementsAsHard(Adesk::kTrue) on the // dictionary. Otherwise, only those entries which // are refered to by hard references in other // wblocked objects, will have been cloned via // those references. // In this example, we will always write out all of // the records. Since TreatElementsAsHard is not // currently persistent, we reset it here each time. // pSrcDict->upgradeOpen(); pSrcDict->setTreatElementsAsHard(Adesk::kTrue); pClone = NULL; pSrcDict->wblockClone(pTo, pClone, idMap, Adesk::kFalse); if (pClone != NULL) pClone->close(); break; case AcDb::kDcInsert: // In INSERT, an entire drawing is cloned, and // "merged" into a pre-existing drawing. This // means that the destination drawing may already // have our dictionary - in which case we have to // merge our entries into the destination // dictionary. So, first we must find out if // the destination NamedObjects dictionary has // our dictionary. // AcDbDictionary *pDestNamedDict; pTo->getNamedObjectsDictionary(pDestNamedDict, AcDb::kForWrite); // Since INSERT does not clone the destination // NamedObjects dictionary, we can use getAt() // on it. // es = pDestNamedDict->getAt(kpDictionary, dictId); // If our dictionary does not yet exist in the // NamedObjects dictionary, which is not itself // cloned, we have to both clone and add our // dictionary to it. Since dictionary entries are // ownership references, all of our entries will // also be cloned at this point, so we are done. // if (es == Acad::eKeyNotFound) { pClone = NULL; pSrcDict->deepClone(pDestNamedDict, pClone, idMap); // Unless we have overridden the deepClone // of our dictionary, we should expect it to // always be cloned here. // if (pClone == NULL) { *pRetStat = Acad::eNullObjectId; break; } pDestNamedDict->setAt(kpDictionary, pClone, dictId); pDestNamedDict->close(); pClone->close(); break; } pDestNamedDict->close(); // Our dictionary already exists in the destination // database, so now we must "merge" the entries // into it. Since we have not cloned our // destination dictionary, its objectIds are not in // flux, and we can use getAt() and setAt() on it. // AcDbDictionary *pDestDict; acdbOpenObject(pDestDict, dictId, AcDb::kForWrite); AcDbObject *pObj, *pObjClone; AcDbDictionaryIterator* pIter; pIter = pSrcDict->newIterator(); for (; !pIter->done(); pIter->next()) { const char *pName = pIter->name(); pIter->getObject(pObj, AcDb::kForRead); // If the dictionary contains any references // and/or other objects have references to it, // you must either use deepClone() or put the // idPairs into the idMap here, so that they // will be in the map for translation. // pObjClone = NULL; pObj->deepClone(pDestDict, pObjClone, idMap); // INSERT usually uses a method of cloning // called CheapClone, where it "moves" objects // into the destination database instead of // actually cloning them. When this happens, // pObj and pObjClone are pointers to the // same object. We only want to close pObj // here if it really is a different object. // if (pObj != pObjClone) pObj->close(); if (pObjClone == NULL) continue; // If the name already exists in our // destination dictionary, it must be changed // to something unique. In this example, the // name is changed to an annonymous entry. // The setAt() method will automatically append // a unique identifier to each name beginning // with "*". It will become something like, // "*S04". // if ( pDestDict->getAt(pName, dictId) == Acad::eKeyNotFound) pDestDict->setAt(pName, pObjClone, dictId); else pDestDict->setAt("*S", pObjClone, dictId); pObjClone->close(); } delete pIter; pDestDict->close(); break; default: break; } pSrcDict->close(); }
void ArxDbgAppEditorReactor::beginDeepCloneXlation( AcDbIdMapping& idMap, Acad::ErrorStatus* es) { m_didTheseDicts.setLogicalLength(0); // reset the dictionaries we have processed AcDbDatabase* origDb; AcDbDatabase* destDb; idMap.origDb(origDb); idMap.destDb(destDb); AcDbObject* clonedObj; AcDbObject* objToClone; // we catch this event so that we can wblock objects that are not entities. // This happens from the class ArxDbgUiTdcWblockClone where you are allowed // to pick non-entities to wblock to a new/existing drawing. AcDbDatabase::wblock() // only allows entities to be in the set of objects passed to it, but you // can manually wblockClone them yourself here. if (idMap.deepCloneContext() == AcDb::kDcWblock) { // see what non-entity objects we have to clone by hand. AcDbObjectIdArray handCloneObjects; m_cloneSet.getObjectsForDatabase(origDb, handCloneObjects); if (handCloneObjects.isEmpty()) return; // walk through the clone set and try to clone // everything. If something is already cloned, // its ok, it won't be cloned again or return an // error, it will just set clonedObj to NULL. CString str; int len = handCloneObjects.length(); for (int i=0; i<len; i++) { clonedObj = NULL; if (acdbOpenAcDbObject(objToClone, handCloneObjects[i], AcDb::kForRead) == Acad::eOk) { objToClone->wblockClone(destDb, clonedObj, idMap, Adesk::kFalse); if (clonedObj != NULL) { acutPrintf(_T("\nArxDbgAppEditorReactor: cloned additional object [%s, %s]"), ArxDbgUtils::objToClassStr(clonedObj), ArxDbgUtils::objToHandleStr(objToClone, str)); clonedObj->close(); } objToClone->close(); } } } // catching this event allows us to correctly bring in our Dictionary Records. // If we don't do this, then they will be orphaned. AutoCAD will not hook up // the cloned dictionary records automatically. else if ((ArxDbgOptions::m_instance.m_doDictRecordInsertByHand) && ((idMap.deepCloneContext() == AcDb::kDcInsert) || (idMap.deepCloneContext() == AcDb::kDcInsertCopy))) { // have to manually find all things we are interested in inserting. // So, look for all ArxDbgDictRecords, if its a dict record, // make sure owner dict is cloned in new database AcDbObjectIdArray objIds; collectAllDictRecords(origDb, objIds); int len = objIds.length(); for (int i=0; i<len; i++) { // find out if object is a dict record Acad::ErrorStatus es; es = acdbOpenObject(objToClone, objIds[i], AcDb::kForRead); if (es == Acad::eOk) { acutPrintf("\nArxDbgAppEditorReactor: hand inserting [%s]", ArxDbgUtils::objToClassStr(objToClone)); // clone the owner dictionary if one of our dictionary records if (objToClone->isKindOf(ArxDbgDbDictRecord::desc())) insertCloneOwnerDict(objToClone->ownerId(), destDb, idMap); objToClone->close(); } } } }
// AsdkEdReactor is derived from AcEditorReactor // void AsdkEdReactor::beginDeepCloneXlation(AcDbIdMapping& idMap, Acad::ErrorStatus* es) { if (idMap.deepCloneContext() == AcDb::kDcWblock && getYorN(_T("Wblock all Text Styles"))) { AcDbDatabase *pOrigDb, *pDestDb; if (idMap.origDb(pOrigDb) != Acad::eOk) return; *es = idMap.destDb(pDestDb); if (*es != Acad::eOk) return; AcDbTextStyleTable *pTsTable; *es = pOrigDb->getSymbolTable(pTsTable, AcDb::kForRead); if (*es != Acad::eOk) return; AcDbTextStyleTableIterator *pTsIter; *es = pTsTable->newIterator(pTsIter); if (*es != Acad::eOk) { pTsTable->close(); return; } AcDbTextStyleTableRecord *pTsRecord; AcDbObject *pClonedObj; for (; !pTsIter->done(); pTsIter->step()) { *es = pTsIter->getRecord(pTsRecord, AcDb::kForRead); if (*es != Acad::eOk) { delete pTsIter; pTsTable->close(); return; } // We don't need to check for already cloned // Records. If the Text Style is already // cloned, wblockClone will return Acad::eOk // and pCloneObj will be NULL. // pClonedObj = NULL; *es = pTsRecord->wblockClone(pDestDb, pClonedObj, idMap, Adesk::kFalse); if (*es != Acad::eOk) { pTsRecord->close(); delete pTsIter; pTsTable->close(); return; } *es = pTsRecord->close(); if (*es != Acad::eOk) { delete pTsIter; pTsTable->close(); return; } if (pClonedObj != NULL) { *es = pClonedObj->close(); if (*es != Acad::eOk) { delete pTsIter; pTsTable->close(); return; } } } delete pTsIter; *es = pTsTable->close(); } }