void ArxDbgAppEditorReactor::insertCloneOwnerDict(const AcDbObjectId& dictId, AcDbDatabase* destDb, AcDbIdMapping& idMap) { // the dictionaries are dealt with as a whole when encountering the // first entry within them. Skip processing if we have already // encountered this one before. if (m_didTheseDicts.contains(dictId)) return; else m_didTheseDicts.append(dictId); // get the name of the dictionary to recreate CString dictName; if (!ArxDbgUtils::lookUpDictEntryName(dictId, dictName)) { ArxDbgUtils::stopAlertBox(_T("ERROR: Couldn't find old dictionary name during Insert!")); return; } // open the source dictionary to be inserted AcDbDictionary* srcDict; if (acdbOpenObject(srcDict, dictId, AcDb::kForRead) != Acad::eOk) { ASSERT(0); return; } // try to open the destiniation dictionary. Since INSERT does // not clone the destination NamedObjects dictionary, we can // use getAt() on it since IDs are not inFlux Acad::ErrorStatus es; AcDbDictionary* destDict = ArxDbgUtils::openDictionaryForRead(dictName, destDb); if (destDict) { es = destDict->upgradeOpen(); if (es == Acad::eOk) insertCloneMergeDicts(srcDict, destDict, idMap); else { ASSERT(0); } destDict->close(); } else { // our dictionary doesn't yet exist in destination database. // Use deepClone to clone it and all of its contents to the // root dictionary of the destination database. AcDbDictionary* rootDictDest; es = destDb->getNamedObjectsDictionary(rootDictDest, AcDb::kForWrite); if (es == Acad::eOk) { AcDbObject* pClone = NULL; srcDict->deepClone(rootDictDest, pClone, idMap); if (pClone != NULL) { AcDbObjectId tmpObjId; es = rootDictDest->setAt(dictName, pClone, tmpObjId); if (es != Acad::eOk) { ArxDbgUtils::stopAlertBox(_T("ERROR: Could not clone destination dictionary!")); ArxDbgUtils::rxErrorAlert(es); } pClone->close(); } rootDictDest->close(); } } srcDict->close(); }
// 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(); }