The AcEditorReactor class provides four notification functions that return control to the application at certain points in the deep clone operation. The following functions are called during all deep clone and wblock clone operations:
The beginDeepClone() function is called after the AcDbIdMapping instance is created and before any objects are cloned. The ID map will be empty, but it can be queried for destDb() and deepCloneContext() at this time.
The beginDeepCloneXlation() function is called after all of the objects in the primary selection set have been cloned and before the references are translated. This is the first time it is possible to see the entire set of what was cloned in the ID map. It is also the time to clone any additional objects and add them to the ID map. Remember that any objects cloned have their object IDs in flux at this point.
The abortDeepClone() function is called at any time between beginDeepClone() and endDeepClone().
The endDeepClone() function is called at the end of the cloning and translation process. The object IDs are no longer in flux. However, this call does not mean that the entities are in their final state for whatever command is being executed. Often the cloned entities are transformed or other operations are performed following the cloning process. There are additional callback functions that can be used to access the entities later, including commandEnded().
In addition to the previous four functions, the following notification functions are provided in the wblock clone operation:
These calls come in the following order with the deep clone functions:
beginWblockObjects() is only sent when the AcDbDatabase::wblockCloneObjects() function has been called and is executing. It is sent once for each source database just before the first object from that database is cloned. For wblockCloneObjects(), the notification sequence is:
There are three types of AcEditorReactor::beginWblock(). They are listed here along with their corresponding AcDbDatabase functions:
WBLOCK*
virtual void AcEditorReactor::beginWblock( AcDbDatabase* pTo, AcDbDatabase* pFrom) Acad::ErrorStatus AcDbDatabase::wblock( AcDbDatabase*& pOutputDatabase)
WBLOCK of a user-defined block
virtual void AcEditorReactor::beginWblock( AcDbDatabase* pTo, AcDbDatabase* pFrom, AcDbObjectId blockId) Acad::ErrorStatus AcDbDatabase::wblock( AcDbDatabase*& pOutputDatabase, AcDbObjectId nObjId)
WBLOCK of a selection set
virtual void AcEditorReactor::beginWblock( AcDbDatabase* pTo, AcDbDatabase* pFrom, const AcGePoint3d& insertionPoint) Acad::ErrorStatus AcDbDatabase::wblock( AcDbDatabase*& pOutputDatabase, const AcDbObjectIdArray& pIdSet, const AcGePoint3d& pPoint3d)
All three versions clone both the model space and paper space AcDbBlockTableRecord before calling beginWblock(). However, for the entities within these block table records, the order of notification will appear to come differently in the first type and last two types. In version one, entities in model space that are being cloned will receive the call for wblockClone() before the AcEditorReactor::beginWblock(). In versions two and three, entities in the AcDbBlockTableRecord or the selection set will get their wblockClone() call after the AcEditorReactor::beginWblock() notification call.
Objects that have been cloned during a partial XBIND are automatically redirected just after endDeepClone() notification. This means that their AcDbObjectIds in the externally referenced database are forwarded to the AcDbObjectIds of the clone objects in the host drawing, and the objects in the externally referenced database are deleted. Objects that reference the forwarded AcDbObjectIds end up referencing the clones in the host drawing. If you need to disable this automatic redirection for your objects, then remove the idPair() from the idMap, for your cloned objects, during endDeepClone() notification.
The following function calls occur during an INSERT or INSERT* command:
These calls come in the following order with the deep clone functions:
The sample code in this section uses the beginDeepCloneXlation() notification function. This sample illustrates how you could write a reactor to add behavior to the WBLOCK command to tell it to include all text styles in the new drawing, instead of only the text styles that are referenced by the entities. It thus shows how to use wblock with nonentities.
AcDbIdMapping has a function, deepCloneContext(), which returns the context in which the deep clone function was called. The contexts are the following:
Copying within a database; uses COPY, ARRAY, MIRROR (if you are not deleting the original), LEADER acquisition, or copy of an INSERT
EXPLODE of a block reference
BLOCK creation
XREF Bind and XBIND
XREF Attach, Resolve, and Reload
SAVEAS when VISRETAIN is set to 1 (only symbol table records are cloned here)
INSERT of a drawing
WBLOCK
AcDbDatabase::deepCloneObjects()
The AcEditorReactor::abortDeepClone() function is called when a call to AcDbDatabase::abortDeepClone() is made.
The following code uses a transient editor reactor derived from AcEditorReactor and overrides the beginDeepCloneXlation() function for the reactor.
// Since AcDbDatabase::wblock() only supports AcDbEntities // in its array of IDs, this code demonstrates how to add // additional objects during beginDeepCloneXlation(). If // it is a WBLOCK command, it asks the user if all text // styles should be wblocked. Otherwise, only those text // styles referenced by entities being wblocked // will be included (wblock's default behavior). // AsdkEdReactor is derived from AcEditorReactor. // void AsdkEdReactor::beginDeepCloneXlation(AcDbIdMapping& idMap, Acad::ErrorStatus* es) { if (idMap.deepCloneContext() == AcDb::kDcWblock && getYorN("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; } // It is not necessary 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(); } }