Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions common/api/core-backend.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,11 @@ export class AnnotationTextStyle extends DefinitionElement {
description?: string;
static deserialize(props: DeserializeEntityArgs): AnnotationTextStyleProps;
static fromJSON(props: AnnotationTextStyleProps, iModel: IModelDb): AnnotationTextStyle;
// (undocumented)
protected static onCloned(context: IModelElementCloneContext, srcProps: AnnotationTextStyleProps, dstProps: AnnotationTextStyleProps): Promise<void>;
protected static onInsert(arg: OnElementPropsArg): void;
protected static onUpdate(arg: OnElementPropsArg): void;
static remapTextStyleId(sourceTextStyleId: Id64String, context: IModelElementCloneContext): Id64String;
static remapTextStyleId(sourceTextStyleId: Id64String, context: IModelElementCloneContext): Promise<Id64String>;
static serialize(props: AnnotationTextStyleProps, iModel: IModelDb): ECSqlRow;
settings: TextStyleSettings;
toJSON(): AnnotationTextStyleProps;
Expand Down Expand Up @@ -1900,7 +1902,7 @@ export abstract class DisplayStyle extends DefinitionElement {
// (undocumented)
loadScheduleScript(): RenderSchedule.ScriptReference | undefined;
// @alpha (undocumented)
protected static onCloned(context: IModelElementCloneContext, sourceElementProps: DisplayStyleProps, targetElementProps: DisplayStyleProps): void;
protected static onCloned(context: IModelElementCloneContext, sourceElementProps: DisplayStyleProps, targetElementProps: DisplayStyleProps): Promise<void>;
// @beta (undocumented)
static serialize(props: DisplayStyleProps, iModel: IModelDb): ECSqlRow;
// (undocumented)
Expand Down Expand Up @@ -1928,7 +1930,7 @@ export class DisplayStyle3d extends DisplayStyle {
static create(iModelDb: IModelDb, definitionModelId: Id64String, name: string, options?: DisplayStyleCreationOptions): DisplayStyle3d;
static insert(iModelDb: IModelDb, definitionModelId: Id64String, name: string, options?: DisplayStyleCreationOptions): Id64String;
// @alpha (undocumented)
protected static onCloned(context: IModelElementCloneContext, sourceElementProps: DisplayStyle3dProps, targetElementProps: DisplayStyle3dProps): void;
protected static onCloned(context: IModelElementCloneContext, sourceElementProps: DisplayStyle3dProps, targetElementProps: DisplayStyle3dProps): Promise<void>;
// (undocumented)
get settings(): DisplayStyle3dSettings;
}
Expand Down Expand Up @@ -2449,7 +2451,7 @@ class Element_2 extends Entity {
// @beta
protected static onChildUpdated(arg: OnChildElementIdArg): void;
// @beta
protected static onCloned(_context: IModelElementCloneContext, _sourceProps: ElementProps, _targetProps: ElementProps): void;
protected static onCloned(_context: IModelElementCloneContext, _sourceProps: ElementProps, _targetProps: ElementProps): Promise<void> | void;
// @beta
protected static onDelete(arg: OnElementIdArg): void;
// @beta
Expand Down Expand Up @@ -3869,7 +3871,7 @@ export class IModelElementCloneContext {
[Symbol.dispose](): void;
constructor(sourceDb: IModelDb, targetDb?: IModelDb);
// @internal
cloneElement(sourceElement: Element_2, cloneOptions?: IModelJsNative.CloneElementOptions): ElementProps;
cloneElement(sourceElement: Element_2, cloneOptions?: IModelJsNative.CloneElementOptions): Promise<ElementProps>;
static create(...args: ConstructorParameters<typeof IModelElementCloneContext>): Promise<IModelElementCloneContext>;
// @deprecated (undocumented)
dispose(): void;
Expand Down Expand Up @@ -5281,7 +5283,7 @@ export class RenderMaterialElement extends DefinitionElement {
static deserialize(props: DeserializeEntityArgs): RenderMaterialProps;
static insert(iModelDb: IModelDb, definitionModelId: Id64String, materialName: string, params: RenderMaterialElementParams): Id64String;
// @beta (undocumented)
protected static onCloned(context: IModelElementCloneContext, sourceProps: ElementProps, targetProps: ElementProps): void;
protected static onCloned(context: IModelElementCloneContext, sourceProps: ElementProps, targetProps: ElementProps): Promise<void>;
paletteName: string;
// @beta
static serialize(props: RenderMaterialProps, iModel: IModelDb): ECSqlRow;
Expand Down Expand Up @@ -5335,7 +5337,7 @@ export class RenderTimeline extends InformationRecordElement {
// (undocumented)
static fromJSON(props: RenderTimelineProps, iModel: IModelDb): RenderTimeline;
// @alpha (undocumented)
protected static onCloned(context: IModelElementCloneContext, sourceProps: RenderTimelineProps, targetProps: RenderTimelineProps): void;
protected static onCloned(context: IModelElementCloneContext, sourceProps: RenderTimelineProps, targetProps: RenderTimelineProps): Promise<void>;
// @beta
static remapScript(context: IModelElementCloneContext, input: RenderSchedule.ScriptProps): RenderSchedule.ScriptProps;
scriptProps: RenderSchedule.ScriptProps;
Expand Down Expand Up @@ -6461,7 +6463,7 @@ export class TextAnnotation2d extends AnnotationElement2d {
// @internal (undocumented)
getTextBlocks(): Iterable<TextBlockAndId>;
// @internal (undocumented)
protected static onCloned(context: IModelElementCloneContext, srcProps: TextAnnotation2dProps, dstProps: TextAnnotation2dProps): void;
protected static onCloned(context: IModelElementCloneContext, srcProps: TextAnnotation2dProps, dstProps: TextAnnotation2dProps): Promise<void>;
// @beta
protected static onInsert(arg: OnElementPropsArg): void;
// @internal (undocumented)
Expand Down Expand Up @@ -6510,7 +6512,7 @@ export class TextAnnotation3d extends GraphicalElement3d {
// @internal (undocumented)
getTextBlocks(): Iterable<TextBlockAndId>;
// @internal (undocumented)
protected static onCloned(context: IModelElementCloneContext, srcProps: TextAnnotation3dProps, dstProps: TextAnnotation3dProps): void;
protected static onCloned(context: IModelElementCloneContext, srcProps: TextAnnotation3dProps, dstProps: TextAnnotation3dProps): Promise<void>;
// @beta
protected static onInsert(arg: OnElementPropsArg): void;
// @internal (undocumented)
Expand Down Expand Up @@ -6952,7 +6954,7 @@ export abstract class ViewDefinition extends DefinitionElement {
loadCategorySelector(): CategorySelector;
loadDisplayStyle(): DisplayStyle;
// @beta (undocumented)
protected static onCloned(context: IModelElementCloneContext, sourceElementProps: ViewDefinitionProps, targetElementProps: ViewDefinitionProps): void;
protected static onCloned(context: IModelElementCloneContext, sourceElementProps: ViewDefinitionProps, targetElementProps: ViewDefinitionProps): Promise<void>;
// @beta (undocumented)
static readonly requiredReferenceKeys: ReadonlyArray<string>;
// @alpha (undocumented)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/core-backend",
"comment": "Element.onCloned can now invoke asynchronous operations.",
"type": "none"
}
],
"packageName": "@itwin/core-backend"
}
8 changes: 4 additions & 4 deletions core/backend/src/DisplayStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ export abstract class DisplayStyle extends DefinitionElement {
}

/** @alpha */
protected static override onCloned(context: IModelElementCloneContext, sourceElementProps: DisplayStyleProps, targetElementProps: DisplayStyleProps): void {
super.onCloned(context, sourceElementProps, targetElementProps);
protected static override async onCloned(context: IModelElementCloneContext, sourceElementProps: DisplayStyleProps, targetElementProps: DisplayStyleProps): Promise<void> {
await super.onCloned(context, sourceElementProps, targetElementProps);

if (!context.isBetweenIModels || !targetElementProps.jsonProperties?.styles)
return;
Expand Down Expand Up @@ -252,8 +252,8 @@ export class DisplayStyle3d extends DisplayStyle {
}

/** @alpha */
protected static override onCloned(context: IModelElementCloneContext, sourceElementProps: DisplayStyle3dProps, targetElementProps: DisplayStyle3dProps): void {
super.onCloned(context, sourceElementProps, targetElementProps);
protected static override async onCloned(context: IModelElementCloneContext, sourceElementProps: DisplayStyle3dProps, targetElementProps: DisplayStyle3dProps): Promise<void> {
await super.onCloned(context, sourceElementProps, targetElementProps);
if (context.isBetweenIModels) {
const convertTexture = (id: string) => Id64.isValidId64(id) ? context.findTargetElementId(id) : id;

Expand Down
6 changes: 3 additions & 3 deletions core/backend/src/Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ export class Element extends Entity {
* @note If you override this method, you must call super.
* @beta
*/
protected static onCloned(_context: IModelElementCloneContext, _sourceProps: ElementProps, _targetProps: ElementProps): void { }
protected static onCloned(_context: IModelElementCloneContext, _sourceProps: ElementProps, _targetProps: ElementProps): Promise<void> | void { }

/** Called when a *root* element in a subgraph is changed and before its outputs are processed.
* This special callback is made when:
Expand Down Expand Up @@ -2167,8 +2167,8 @@ export class RenderTimeline extends InformationRecordElement {
}

/** @alpha */
protected static override onCloned(context: IModelElementCloneContext, sourceProps: RenderTimelineProps, targetProps: RenderTimelineProps): void {
super.onCloned(context, sourceProps, targetProps);
protected static override async onCloned(context: IModelElementCloneContext, sourceProps: RenderTimelineProps, targetProps: RenderTimelineProps): Promise<void> {
await super.onCloned(context, sourceProps, targetProps);
if (context.isBetweenIModels)
targetProps.script = JSON.stringify(this.remapScript(context, this.parseScriptProps(targetProps.script)));
}
Expand Down
4 changes: 2 additions & 2 deletions core/backend/src/IModelElementCloneContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export class IModelElementCloneContext {
/** Clone the specified source Element into ElementProps for the target iModel.
* @internal
*/
public cloneElement(sourceElement: Element, cloneOptions?: IModelJsNative.CloneElementOptions): ElementProps {
public async cloneElement(sourceElement: Element, cloneOptions?: IModelJsNative.CloneElementOptions): Promise<ElementProps> {
const targetElementProps: ElementProps = this._nativeContext.cloneElement(sourceElement.id, cloneOptions);
// Ensure that all NavigationProperties in targetElementProps have a defined value so "clearing" changes will be part of the JSON used for update
// eslint-disable-next-line @typescript-eslint/no-deprecated
Expand All @@ -170,7 +170,7 @@ export class IModelElementCloneContext {
}
const jsClass = this.sourceDb.getJsClass<typeof Element>(sourceElement.classFullName);
// eslint-disable-next-line @typescript-eslint/dot-notation
jsClass["onCloned"](this, sourceElement.toJSON(), targetElementProps);
await jsClass["onCloned"](this, sourceElement.toJSON(), targetElementProps);
return targetElementProps;
}

Expand Down
4 changes: 2 additions & 2 deletions core/backend/src/Material.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ export class RenderMaterialElement extends DefinitionElement {
}

/** @beta */
protected static override onCloned(context: IModelElementCloneContext, sourceProps: ElementProps, targetProps: ElementProps) {
super.onCloned(context, sourceProps, targetProps);
protected static override async onCloned(context: IModelElementCloneContext, sourceProps: ElementProps, targetProps: ElementProps) {
await super.onCloned(context, sourceProps, targetProps);
for (const mapName in sourceProps.jsonProperties?.materialAssets?.renderMaterial?.Map ?? {}) {
if (typeof mapName !== "string")
continue;
Expand Down
4 changes: 2 additions & 2 deletions core/backend/src/ViewDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,8 @@ export abstract class ViewDefinition extends DefinitionElement {
};

/** @beta */
protected static override onCloned(context: IModelElementCloneContext, sourceElementProps: ViewDefinitionProps, targetElementProps: ViewDefinitionProps): void {
super.onCloned(context, sourceElementProps, targetElementProps);
protected static override async onCloned(context: IModelElementCloneContext, sourceElementProps: ViewDefinitionProps, targetElementProps: ViewDefinitionProps): Promise<void> {
await super.onCloned(context, sourceElementProps, targetElementProps);
if (context.isBetweenIModels && targetElementProps.jsonProperties && targetElementProps.jsonProperties.viewDetails) {
const acsId: Id64String = Id64.fromJSON(targetElementProps.jsonProperties.viewDetails.acs);
if (Id64.isValidId64(acsId)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export class ElementDrivesTextAnnotation extends ElementDrivesElement {

/** When copying an [[ITextAnnotation]] from one iModel into another, remaps the element Ids in any [FieldPropertyHost]($common) within the cloned element
* so that they refer to elements in the `context`'s target iModel, and sets any Ids that cannot be remapped to [Id64.invalid]($bentley).
* Implementations of `ITextAnnotation` should invoke this function from their implementations of [[Element._onCloned]].
* Implementations of `ITextAnnotation` should invoke this function from their implementations of [[Element.onCloned]].
*/
public static remapFields(clone: ITextAnnotation, context: IModelElementCloneContext): void {
if (!context.isBetweenIModels) {
Expand Down
43 changes: 31 additions & 12 deletions core/backend/src/annotations/TextAnnotationElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,15 +297,15 @@ export class TextAnnotation2d extends AnnotationElement2d /* implements ITextAnn
}

/** @internal */
protected static override onCloned(context: IModelElementCloneContext, srcProps: TextAnnotation2dProps, dstProps: TextAnnotation2dProps): void {
super.onCloned(context, srcProps, dstProps);
protected static override async onCloned(context: IModelElementCloneContext, srcProps: TextAnnotation2dProps, dstProps: TextAnnotation2dProps): Promise<void> {
await super.onCloned(context, srcProps, dstProps);

const srcElem = TextAnnotation2d.fromJSON(srcProps, context.sourceDb);
ElementDrivesTextAnnotation.remapFields(srcElem, context);
const anno = srcElem.getAnnotation();
dstProps.textAnnotationData = anno ? JSON.stringify({ version: TEXT_ANNOTATION_JSON_VERSION, data: anno.toJSON() }) : undefined;

remapTextStyle(context, srcElem, dstProps);
return remapTextStyle(context, srcElem, dstProps);
}
}

Expand Down Expand Up @@ -484,24 +484,24 @@ export class TextAnnotation3d extends GraphicalElement3d /* implements ITextAnno
}

/** @internal */
protected static override onCloned(context: IModelElementCloneContext, srcProps: TextAnnotation3dProps, dstProps: TextAnnotation3dProps): void {
super.onCloned(context, srcProps, dstProps);
protected static override async onCloned(context: IModelElementCloneContext, srcProps: TextAnnotation3dProps, dstProps: TextAnnotation3dProps): Promise<void> {
await super.onCloned(context, srcProps, dstProps);

const srcElem = TextAnnotation3d.fromJSON(srcProps, context.sourceDb);
ElementDrivesTextAnnotation.remapFields(srcElem, context);
const anno = srcElem.getAnnotation();
dstProps.textAnnotationData = anno ? JSON.stringify({ version: TEXT_ANNOTATION_JSON_VERSION, data: anno.toJSON() }) : undefined;

remapTextStyle(context, srcElem, dstProps);
return remapTextStyle(context, srcElem, dstProps);
}
}

function remapTextStyle(
async function remapTextStyle(
context: IModelElementCloneContext,
srcElem: TextAnnotation2d | TextAnnotation3d,
dstProps: TextAnnotation2dProps | TextAnnotation3dProps
): void {
const dstStyleId = AnnotationTextStyle.remapTextStyleId(srcElem.defaultTextStyle?.id ?? Id64.invalid, context);
): Promise<void> {
const dstStyleId = await AnnotationTextStyle.remapTextStyleId(srcElem.defaultTextStyle?.id ?? Id64.invalid, context);
dstProps.defaultTextStyle = Id64.isValid(dstStyleId) ? new TextAnnotationUsesTextStyleByDefault(dstStyleId).toJSON() : undefined;
}

Expand Down Expand Up @@ -721,10 +721,10 @@ export class AnnotationTextStyle extends DefinitionElement {
* corresponding to `sourceTextStyleId`, or [Id64.invalid]($bentley) if no corresponding text style exists.
* If a text style with the same [Code]($common) exists in the target iModel, the style Id will be remapped to refer to that style.
* Otherwise, a copy of the style will be imported into the target iModel and its element Id returned.
* Implementations of [[ITextAnnotation]] should invoke this function when implementing their [[Element._onCloned]] method.
* Implementations of [[ITextAnnotation]] should invoke this function when implementing their [[Element.onCloned]] method.
* @throws Error if an attempt to import the text style failed.
*/
public static remapTextStyleId(sourceTextStyleId: Id64String, context: IModelElementCloneContext): Id64String {
public static async remapTextStyleId(sourceTextStyleId: Id64String, context: IModelElementCloneContext): Promise<Id64String> {
// No remapping necessary if there's no text style or we're not copying to a different iModel.
if (!Id64.isValid(sourceTextStyleId) || !context.isBetweenIModels) {
return sourceTextStyleId;
Expand All @@ -749,9 +749,28 @@ export class AnnotationTextStyle extends DefinitionElement {
}

// Copy the style into the target iModel and remap its Id.
const dstStyleProps = context.cloneElement(srcStyle);
const dstStyleProps = await context.cloneElement(srcStyle);
dstStyleId = context.targetDb.elements.insertElement(dstStyleProps);
context.remapElement(sourceTextStyleId, dstStyleId);
return dstStyleId;
}

protected static override async onCloned(context: IModelElementCloneContext, srcProps: AnnotationTextStyleProps, dstProps: AnnotationTextStyleProps): Promise<void> {
await super.onCloned(context, srcProps, dstProps);
if (!context.isBetweenIModels) {
return;
}

const settingsProps = AnnotationTextStyle.parseTextStyleSettings(srcProps.settings);
const font = TextStyleSettings.fromJSON(settingsProps?.data).font;

const fontsToEmbed = [];
for (const file of context.sourceDb.fonts.queryEmbeddedFontFiles()) {
if (file.type === font.type && file.faces.some((face) => face.familyName === font.name)) {
fontsToEmbed.push(file);
}
}

await Promise.all(fontsToEmbed.map(async (file) => context.targetDb.fonts.embedFontFile({ file })));
}
}
Loading