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();
}
Example #2
0
// 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();
}