From 05b8abc2ae48ea3fa0706b98e8aa36108538a378 Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Sat, 10 Nov 2018 12:48:31 +0100
Subject: [PATCH] mol-state: added Transform.tag, refactoring

---
 src/mol-plugin/ui/controls.tsx   | 28 +++++++++++---------
 src/mol-state/object.ts          |  8 +++---
 src/mol-state/state.ts           | 44 +++++++++++++++++++-------------
 src/mol-state/state/selection.ts | 12 ++++-----
 src/mol-state/transform.ts       | 17 +++++++-----
 5 files changed, 64 insertions(+), 45 deletions(-)

diff --git a/src/mol-plugin/ui/controls.tsx b/src/mol-plugin/ui/controls.tsx
index 42d6dc0ff..1e6e881ad 100644
--- a/src/mol-plugin/ui/controls.tsx
+++ b/src/mol-plugin/ui/controls.tsx
@@ -91,21 +91,24 @@ export class _test_CreateTransform extends React.Component<{ plugin: PluginConte
 }
 
 export class _test_UpdateTransform extends React.Component<{ plugin: PluginContext, state: State, nodeRef: Transform.Ref }, { params: any }> {
-    private getTransform() {
-        return this.props.state.tree.nodes.get(this.props.nodeRef)!;
+    private getCell(ref?: string) {
+        return this.props.state.cells.get(ref || this.props.nodeRef)!;
     }
 
-    private getParamDef() {
-        const def = this.getTransform().transformer.definition;
-        if (!def.params || !def.params.controls) return void 0;
-
-        const src = this.props.state.select(q => q.byRef(this.props.nodeRef).ancestorOfType(def.from))[0];
-
-        // StateSelection.ancestorOfType(this.props.nodeRef, def.from).select(this.props.plugin.state.data)[0];
+    private getDefParams() {
+        const cell = this.getCell();
+        if (!cell) return { };
+        return cell.transform.params;
+    }
 
-        console.log(src, def.from);
+    private getParamDef() {
+        const cell = this.getCell();
+        const def = cell.transform.transformer.definition;
 
+        if (!cell.sourceRef || !def.params || !def.params.controls) return void 0;
+        const src = this.getCell(cell.sourceRef);
         if (!src || !src.obj) return void 0;
+
         return def.params.controls(src.obj, this.props.plugin);
     }
 
@@ -119,10 +122,11 @@ export class _test_UpdateTransform extends React.Component<{ plugin: PluginConte
     //     if (t) this.setState({ params: t.value.params });
     // }
 
-    state = { params: this.getTransform() ? this.getTransform().params : { } };
+    state = { params: this.getDefParams() };
 
     render() {
-        const transform = this.getTransform();
+        const cell = this.getCell();
+        const transform = cell.transform;
         if (!transform || transform.ref === Transform.RootRef) {
             return <div />;
         }
diff --git a/src/mol-state/object.ts b/src/mol-state/object.ts
index 831885b05..a7d3bbc85 100644
--- a/src/mol-state/object.ts
+++ b/src/mol-state/object.ts
@@ -36,12 +36,14 @@ namespace StateObject {
 }
 
 interface StateObjectCell {
-    ref: Transform.Ref,
+    transform: Transform,
+
+    // Which object was used as a parent to create data in this cell
+    sourceRef: Transform.Ref | undefined,
+
     version: string
     status: StateObjectCell.Status,
 
-    state: unknown,
-
     errorText?: string,
     obj?: StateObject
 }
diff --git a/src/mol-state/state.ts b/src/mol-state/state.ts
index 57693439e..f8a54885b 100644
--- a/src/mol-state/state.ts
+++ b/src/mol-state/state.ts
@@ -109,11 +109,11 @@ class State {
         const root = tree.root;
 
         (this.cells as Map<Transform.Ref, StateObjectCell>).set(root.ref, {
-            ref: root.ref,
+            transform: root,
+            sourceRef: void 0,
             obj: rootObject,
             status: 'ok',
-            version: root.version,
-            state: { ...StateObjectCell.DefaultState }
+            version: root.version
         });
 
         this.globalContext = params && params.globalContext;
@@ -216,11 +216,11 @@ function _initCellsVisitor(transform: Transform, _: any, ctx: UpdateContext) {
     if (ctx.cells.has(transform.ref)) return;
 
     const obj: StateObjectCell = {
-        ref: transform.ref,
+        transform,
+        sourceRef: void 0,
         status: 'pending',
         version: UUID.create(),
-        errorText: void 0,
-        state: { ...StateObjectCell.DefaultState, ...transform.cellState }
+        errorText: void 0
     };
     ctx.cells.set(transform.ref, obj);
 
@@ -250,15 +250,16 @@ function doError(ctx: UpdateContext, ref: Ref, errorText: string) {
     }
 }
 
-function findAncestor(tree: StateTree, cells: State.Cells, root: Ref, types: { type: StateObject.Type }[]): StateObject {
+function findAncestor(tree: StateTree, cells: State.Cells, root: Ref, types: { type: StateObject.Type }[]): StateObjectCell | undefined {
     let current = tree.nodes.get(root)!;
     while (true) {
         current = tree.nodes.get(current.parent)!;
+        const cell = cells.get(current.ref)!;
+        if (!cell.obj) return void 0;
+        for (const t of types) if (cell.obj.type === t.type) return cells.get(current.ref)!;
         if (current.ref === Transform.RootRef) {
-            return cells.get(Transform.RootRef)!.obj!;
+            return void 0;
         }
-        const obj = cells.get(current.ref)!.obj!;
-        for (const t of types) if (obj.type === t.type) return cells.get(current.ref)!.obj!;
     }
 }
 
@@ -289,23 +290,30 @@ async function updateSubtree(ctx: UpdateContext, root: Ref) {
 }
 
 async function updateNode(ctx: UpdateContext, currentRef: Ref) {
-    const { oldTree, tree, cells } = ctx;
+    const { oldTree, tree } = ctx;
     const transform = tree.nodes.get(currentRef);
-    const parent = findAncestor(tree, cells, currentRef, transform.transformer.definition.from);
+    const parentCell = findAncestor(tree, ctx.cells, currentRef, transform.transformer.definition.from);
+
+    if (!parentCell) {
+        throw new Error(`No suitable parent found for '${currentRef}'`);
+    }
+
+    const parent = parentCell.obj!;
+    const current = ctx.cells.get(currentRef)!;
+    current.sourceRef = parentCell.transform.ref;
+
     // console.log('parent', transform.transformer.id, transform.transformer.definition.from[0].type, parent ? parent.ref : 'undefined')
-    if (!oldTree.nodes.has(currentRef) || !cells.has(currentRef)) {
+    if (!oldTree.nodes.has(currentRef)) {
         // console.log('creating...', transform.transformer.id, oldTree.nodes.has(currentRef), objects.has(currentRef));
         const obj = await createObject(ctx, currentRef, transform.transformer, parent, transform.params);
-        const cell = cells.get(currentRef)!;
-        cell.obj = obj;
-        cell.version = transform.version;
+        current.obj = obj;
+        current.version = transform.version;
 
         return { action: 'created', obj };
     } else {
-        const current = cells.get(currentRef)!;
         const oldParams = oldTree.nodes.get(currentRef)!.params;
 
-        const updateKind = current.status === 'ok' || current.ref === Transform.RootRef
+        const updateKind = current.status === 'ok' || current.transform.ref === Transform.RootRef
             ? await updateObject(ctx, currentRef, transform.transformer, parent, current.obj!, oldParams, transform.params)
             : Transformer.UpdateResult.Recreate;
 
diff --git a/src/mol-state/state/selection.ts b/src/mol-state/state/selection.ts
index 9bbacebc3..6a045890d 100644
--- a/src/mol-state/state/selection.ts
+++ b/src/mol-state/state/selection.ts
@@ -123,8 +123,8 @@ namespace StateSelection {
             const set = new Set<string>();
             const ret: StateObjectCell[] = [];
             for (const n of q(state)) {
-                if (!set.has(n.ref)) {
-                    set.add(n.ref);
+                if (!set.has(n.transform.ref)) {
+                    set.add(n.transform.ref);
                     ret.push(n);
                 }
             }
@@ -151,7 +151,7 @@ namespace StateSelection {
     export function subtree(b: Selector) {
         return flatMap(b, (n, s) => {
             const nodes = [] as string[];
-            StateTree.doPreOrder(s.tree, s.tree.nodes.get(n.ref), nodes, (x, _, ctx) => { ctx.push(x.ref) });
+            StateTree.doPreOrder(s.tree, s.tree.nodes.get(n.transform.ref), nodes, (x, _, ctx) => { ctx.push(x.ref) });
             return nodes.map(x => s.cells.get(x)!);
         });
     }
@@ -160,7 +160,7 @@ namespace StateSelection {
     export function children(b: Selector) {
         return flatMap(b, (n, s) => {
             const nodes: StateObjectCell[] = [];
-            s.tree.children.get(n.ref).forEach(c => nodes.push(s.cells.get(c!)!));
+            s.tree.children.get(n.transform.ref).forEach(c => nodes.push(s.cells.get(c!)!));
             return nodes;
         });
     }
@@ -169,10 +169,10 @@ namespace StateSelection {
     export function ofType(b: Selector, t: StateObject.Type) { return filter(b, n => n.obj ? n.obj.type === t : false); }
 
     registerModifier('ancestorOfType', ancestorOfType);
-    export function ancestorOfType(b: Selector, types: StateObject.Ctor[]) { return unique(mapEntity(b, (n, s) => findAncestorOfType(s, n.ref, types))); }
+    export function ancestorOfType(b: Selector, types: StateObject.Ctor[]) { return unique(mapEntity(b, (n, s) => findAncestorOfType(s, n.transform.ref, types))); }
 
     registerModifier('parent', parent);
-    export function parent(b: Selector) { return unique(mapEntity(b, (n, s) => s.cells.get(s.tree.nodes.get(n.ref)!.parent))); }
+    export function parent(b: Selector) { return unique(mapEntity(b, (n, s) => s.cells.get(s.tree.nodes.get(n.transform.ref)!.parent))); }
 
     function findAncestorOfType({ tree, cells }: State, root: string, types: StateObject.Ctor[]): StateObjectCell | undefined {
         let current = tree.nodes.get(root)!, len = types.length;
diff --git a/src/mol-state/transform.ts b/src/mol-state/transform.ts
index 791eaf3a2..c0203be3d 100644
--- a/src/mol-state/transform.ts
+++ b/src/mol-state/transform.ts
@@ -14,7 +14,8 @@ export interface Transform<A extends StateObject = StateObject, B extends StateO
     readonly params: P,
     readonly ref: Transform.Ref,
     readonly version: string,
-    readonly cellState?: Partial<StateObjectCell.State>
+    readonly cellState?: Partial<StateObjectCell.State>,
+    readonly tag?: string
 }
 
 export namespace Transform {
@@ -22,7 +23,7 @@ export namespace Transform {
 
     export const RootRef = '-=root=-' as Ref;
 
-    export interface Options { ref?: Ref, cellState?: Partial<StateObjectCell.State> }
+    export interface Options { ref?: Ref, tag?: string, cellState?: Partial<StateObjectCell.State> }
 
     export function create<A extends StateObject, B extends StateObject, P>(parent: Ref, transformer: Transformer<A, B, P>, params?: P, options?: Options): Transform<A, B, P> {
         const ref = options && options.ref ? options.ref : UUID.create() as string as Ref;
@@ -32,7 +33,8 @@ export namespace Transform {
             params: params || {} as any,
             ref,
             version: UUID.create(),
-            cellState: options && options.cellState
+            cellState: options && options.cellState,
+            tag: options && options.tag
         }
     }
 
@@ -50,7 +52,8 @@ export namespace Transform {
         params: any,
         ref: string,
         version: string,
-        cellState?: Partial<StateObjectCell.State>
+        cellState?: Partial<StateObjectCell.State>,
+        tag?: string
     }
 
     function _id(x: any) { return x; }
@@ -64,7 +67,8 @@ export namespace Transform {
             params: pToJson(t.params),
             ref: t.ref,
             version: t.version,
-            cellState: t.cellState
+            cellState: t.cellState,
+            tag: t.tag
         };
     }
 
@@ -79,7 +83,8 @@ export namespace Transform {
             params: pFromJson(t.params),
             ref: t.ref as Ref,
             version: t.version,
-            cellState: t.cellState
+            cellState: t.cellState,
+            tag: t.tag
         };
     }
 }
\ No newline at end of file
-- 
GitLab