reparentElements method

EditResult reparentElements(
  1. Iterable<String> elementIds, {
  2. String? parentId,
  3. DiagramPoint delta = DiagramPoint.zero,
})

Transfers ownership while preserving world geometry and nested contents. A nonzero delta translates the complete subtree in the same transaction. Locked or immovable descendants reject that movement atomically.

Implementation

EditResult reparentElements(
  Iterable<String> elementIds, {
  String? parentId,
  DiagramPoint delta = DiagramPoint.zero,
}) {
  if (!delta.x.isFinite || !delta.y.isFinite) {
    throw ArgumentError.value(delta, 'delta', 'Use a finite movement.');
  }
  if (store.isInteracting) {
    return const EditResult.denied(reason: 'Finish the active edit first.');
  }
  final document = store.state.document;
  final scene = store.scene;
  if (parentId != null) {
    final parent = scene.shapeById(parentId);
    if (parent == null ||
        !scene.isVisible(parentId) ||
        parent.source.isCollapsed ||
        parent.container == null) {
      return const EditResult.denied(reason: 'Choose an expanded container.');
    }
  }
  final ids = elementIds.toSet();
  for (final id in ids) {
    final resolved = scene.elementById(id);
    if (resolved == null || !scene.isVisible(id)) {
      return const EditResult.denied(
        reason: 'Choose visible objects to transfer.',
      );
    }
  }
  final roots = diagramSelectionRoots(document, ids);
  if (parentId != null &&
      diagramSelectionClosure(document, roots).containsKey(parentId)) {
    return const EditResult.denied(
      reason: 'A container cannot become its own descendant.',
    );
  }
  final movedIds = delta == DiagramPoint.zero
      ? roots
      : diagramSelectionClosure(document, roots).keys.toSet();
  for (final id in movedIds) {
    if (delta != DiagramPoint.zero) {
      final resolved = scene.elementById(id);
      if (resolved == null ||
          (resolved is ResolvedFramedElement && !resolved.behavior.movable)) {
        return const EditResult.denied(
          reason: 'Enable movement of the contents first.',
        );
      }
    }
  }
  final transaction = DiagramGrouping.moveToContainers(
    document: document,
    elements: movedIds.map((id) => document.elementById(id)!),
    delta: delta,
    parents: {for (final id in roots) id: parentId},
  );
  if (transaction.steps.isEmpty) return const EditResult.allow();
  return store.edits.dispatch(
    transaction,
    expectedRevision: document.revision,
  );
}