diff --git a/src/mol-state/state.ts b/src/mol-state/state.ts index 56385e82a6c7915643ea21e5e5af192ab9321a4c..8286db855dfeff046f7a10cf315cdc075e336286 100644 --- a/src/mol-state/state.ts +++ b/src/mol-state/state.ts @@ -224,7 +224,7 @@ async function update(ctx: UpdateContext) { } if (hasCurrent) { - const newCurrent = findNewCurrent(ctx.oldTree, current, deletes); + const newCurrent = findNewCurrent(ctx.oldTree, current, deletes, ctx.cells); ctx.parent.setCurrent(newCurrent); } @@ -270,7 +270,7 @@ async function update(ctx: UpdateContext) { await updateSubtree(ctx, root); } - let newCurrent: Transform.Ref | undefined; + let newCurrent: Transform.Ref | undefined = ctx.newCurrent; // Raise object updated events for (const update of ctx.results) { if (update.action === 'created') { @@ -286,8 +286,19 @@ async function update(ctx: UpdateContext) { } } - if (ctx.newCurrent) ctx.parent.setCurrent(ctx.newCurrent); - else if (newCurrent) ctx.parent.setCurrent(newCurrent); + if (newCurrent) ctx.parent.setCurrent(newCurrent); + else { + // check if old current or its parent hasn't become null + const current = ctx.parent.current; + const currentCell = ctx.cells.get(current); + if (currentCell && ( + currentCell.obj === StateObject.Null + || (currentCell.status === 'error' && currentCell.errorText === ParentNullErrorText))) { + newCurrent = findNewCurrent(ctx.oldTree, current, [], ctx.cells); + ctx.parent.setCurrent(newCurrent); + } + } + return deletes.length > 0 || roots.length > 0 || ctx.changed; } @@ -300,6 +311,7 @@ function findUpdateRoots(cells: Map<Transform.Ref, StateObjectCell>, tree: State function findUpdateRootsVisitor(n: Transform, _: any, s: { roots: Ref[], cells: Map<Ref, StateObjectCell> }) { const cell = s.cells.get(n.ref); + if (cell && cell.obj === StateObject.Null) return false; if (!cell || cell.version !== n.version || cell.status === 'error') { s.roots.push(n.ref); return false; @@ -369,12 +381,12 @@ function initCells(ctx: UpdateContext, roots: Ref[]) { return initCtx.added; } -function findNewCurrent(tree: StateTree, start: Ref, deletes: Ref[]) { +function findNewCurrent(tree: StateTree, start: Ref, deletes: Ref[], cells: Map<Ref, StateObjectCell>) { const deleteSet = new Set(deletes); - return _findNewCurrent(tree, start, deleteSet); + return _findNewCurrent(tree, start, deleteSet, cells); } -function _findNewCurrent(tree: StateTree, ref: Ref, deletes: Set<Ref>): Ref { +function _findNewCurrent(tree: StateTree, ref: Ref, deletes: Set<Ref>, cells: Map<Ref, StateObjectCell>): Ref { if (ref === Transform.RootRef) return ref; const node = tree.transforms.get(ref)!; @@ -387,6 +399,10 @@ function _findNewCurrent(tree: StateTree, ref: Ref, deletes: Set<Ref>): Ref { if (s.done) break; if (deletes.has(s.value)) continue; + const cell = cells.get(s.value); + if (!cell || cell.status === 'error' || cell.obj === StateObject.Null) { + continue; + } const t = tree.transforms.get(s.value); if (t.props && t.props.isGhost) continue; @@ -402,7 +418,7 @@ function _findNewCurrent(tree: StateTree, ref: Ref, deletes: Set<Ref>): Ref { } if (prevCandidate) return prevCandidate; - return _findNewCurrent(tree, node.parent, deletes); + return _findNewCurrent(tree, node.parent, deletes, cells); } /** Set status and error text of the cell. Remove all existing objects in the subtree. */ @@ -440,6 +456,8 @@ type UpdateNodeResult = | { ref: Ref, action: 'replaced', oldObj?: StateObject, obj: StateObject } | { action: 'none' } +const ParentNullErrorText = 'Parent is null'; + async function updateSubtree(ctx: UpdateContext, root: Ref) { setCellStatus(ctx, root, 'processing'); @@ -463,11 +481,6 @@ async function updateSubtree(ctx: UpdateContext, root: Ref) { isNull = update.obj === StateObject.Null; ctx.parent.events.log.next(LogEntry.info(`Updated ${update.obj.label} in ${formatTimespan(time)}.`)); } - - if (isNull && !ctx.newCurrent) { - // TODO: is this ok? - ctx.newCurrent = findNewCurrent(ctx.tree, root, [root]); - } } catch (e) { ctx.changed = true; if (!ctx.hadError) ctx.newCurrent = root; @@ -479,7 +492,7 @@ async function updateSubtree(ctx: UpdateContext, root: Ref) { while (true) { const next = children.next(); if (next.done) return; - if (isNull) doError(ctx, next.value, 'Parent is null', true); + if (isNull) doError(ctx, next.value, ParentNullErrorText, true); else await updateSubtree(ctx, next.value); } }