UNPKG

@itwin/core-backend

Version:
157 lines • 8.79 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Elements */ Object.defineProperty(exports, "__esModule", { value: true }); exports.TextAnnotationUsesTextStyleByDefault = exports.ElementDrivesTextAnnotation = void 0; exports.isITextAnnotation = isITextAnnotation; const core_common_1 = require("@itwin/core-common"); const Relationship_1 = require("../Relationship"); const fields_1 = require("../internal/annotations/fields"); const core_bentley_1 = require("@itwin/core-bentley"); const ecschema_metadata_1 = require("@itwin/ecschema-metadata"); // ElementDrivesTextAnnotation was introduced in this version of BisCore - iModels with earlier versions cannot support field dependencies. const minBisCoreVersion = new ecschema_metadata_1.ECVersion(1, 0, 22); /** Returns `true` if the specified `element` implements [[ITextAnnotation]]. * @beta */ function isITextAnnotation(element) { return ["getTextBlocks", "updateTextBlocks"].every((x) => x in element && typeof element[x] === "function"); } /** A relationship in which the source element hosts one or more properties that are displayed by a target [[ITextAnnotation]] element. * This relationship is used to automatically update the [FieldRun]($common)s contained in the target element when the source element is modified. * An [[ITextAnnotation]] element should invoke [[updateFieldDependencies]] from its [[Element.onInserted]] and [[Element.onUpdated]] functions to * establish or update the relationships required for the [FieldRun]($common)s it contains. * @note This relationship was introduced in version 01.00.22 of the BisCore schema. [FieldRun]($common)s created in iModels that have not been upgraded to * that version or newer will not automatically update. Use [[isSupportedForIModel]] to check. * @beta */ class ElementDrivesTextAnnotation extends Relationship_1.ElementDrivesElement { static get className() { return "ElementDrivesTextAnnotation"; } /** @internal */ static onRootChanged(props, iModel) { (0, fields_1.updateElementFields)(props, iModel, false); } /** @internal */ static onDeletedDependency(props, iModel) { (0, fields_1.updateElementFields)(props, iModel, true); } /** Returns true if `iModel` contains a version of the BisCore schema new enough to support this relationship. * If not, the schema should be updated before inserting any [FieldRun]($common)s, or those runs will not * update when the source element changes. */ static isSupportedForIModel(iModel) { return iModel.meetsMinimumSchemaVersion("BisCore", minBisCoreVersion); } /** Examines all of the [FieldRun]($common)s within the specified [[ITextAnnotation]] and ensures that the appropriate * `ElementDrivesTextAnnotation` relationships exist between the fields' source elements and this target element. * It also deletes any stale relationships left over from fields that were deleted or whose source elements changed. */ static updateFieldDependencies(annotationElementId, iModel) { const annotationElement = iModel.elements.tryGetElement(annotationElementId); if (!annotationElement || !isITextAnnotation(annotationElement)) { return; } // The native layer will allow us to insert relationships to invalid or non-existent source elements...errors will arise later. Prevent it. function isValidSourceId(id) { if (!core_bentley_1.Id64.isValidId64(id)) { return false; } // eslint-disable-next-line @typescript-eslint/no-deprecated return iModel.withPreparedStatement("SELECT CodeValue FROM BisCore.Element WHERE ECInstanceId=?", (stmt) => { stmt.bindId(1, id); return core_bentley_1.DbResult.BE_SQLITE_ROW === stmt.step(); }); } const sourceToRelationship = new Map(); const blocks = annotationElement.getTextBlocks(); let haveFields = false; for (const block of blocks) { for (const { child } of (0, core_common_1.traverseTextBlockComponent)(block.textBlock)) { if (child.type === "field") { haveFields = true; if (isValidSourceId(child.propertyHost.elementId)) { sourceToRelationship.set(child.propertyHost.elementId, null); } } } } if (haveFields) { iModel.requireMinimumSchemaVersion("BisCore", minBisCoreVersion, "Text fields"); (0, fields_1.updateAllFields)(annotationElementId, iModel); } const staleRelationships = new Set(); if (this.isSupportedForIModel(iModel)) { // eslint-disable-next-line @typescript-eslint/no-deprecated annotationElement.iModel.withPreparedStatement(`SELECT ECInstanceId, SourceECInstanceId FROM BisCore.ElementDrivesTextAnnotation WHERE TargetECInstanceId=${annotationElement.id}`, (stmt) => { while (core_bentley_1.DbResult.BE_SQLITE_ROW === stmt.step()) { const relationshipId = stmt.getValue(0).getId(); const sourceId = stmt.getValue(1).getId(); if (sourceToRelationship.has(sourceId)) { sourceToRelationship.set(sourceId, relationshipId); } else { staleRelationships.add(relationshipId); } } }); } for (const [sourceId, relationshipId] of sourceToRelationship) { if (relationshipId === null) { ElementDrivesTextAnnotation.create(annotationElement.iModel, sourceId, annotationElement.id).insert(); } } if (staleRelationships.size > 0) { const staleRelationshipProps = Array.from(staleRelationships).map(relationshipId => annotationElement.iModel.relationships.getInstanceProps("BisCore.ElementDrivesTextAnnotation", relationshipId)); annotationElement.iModel.relationships.deleteInstances(staleRelationshipProps); } } /** Recompute the display strings of all [FieldRun]($common)s in a [TextBlock]($common). * @returns the number of fields whose display strings were modified. * @throws Error if evaluation of any field fails. */ static evaluateFields(args) { return (0, fields_1.updateFields)(args.block, (0, fields_1.createUpdateContext)(undefined, args.iModel, false)); } /** 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]]. */ static remapFields(clone, context) { if (!context.isBetweenIModels) { return; } const updatedBlocks = []; for (const block of clone.getTextBlocks()) { let anyUpdated = false; for (const { child } of (0, core_common_1.traverseTextBlockComponent)(block.textBlock)) { if (child.type === "field") { child.propertyHost.elementId = context.findTargetElementId(child.propertyHost.elementId); anyUpdated = true; } } if (anyUpdated) { updatedBlocks.push(block); } } if (updatedBlocks.length > 0) { clone.updateTextBlocks(updatedBlocks); } } } exports.ElementDrivesTextAnnotation = ElementDrivesTextAnnotation; /** Relationship indicating that the [[AnnotationTextStyle]] is being used as the default style for the [[ITextAnnotation]]. * @beta */ class TextAnnotationUsesTextStyleByDefault extends core_common_1.RelatedElement { static classFullName = "BisCore:TextAnnotationUsesTextStyleByDefault"; constructor(annotationTextStyleId, relClassName = TextAnnotationUsesTextStyleByDefault.classFullName) { super({ id: annotationTextStyleId, relClassName }); } } exports.TextAnnotationUsesTextStyleByDefault = TextAnnotationUsesTextStyleByDefault; //# sourceMappingURL=ElementDrivesTextAnnotation.js.map