فهرست منبع

Fix some bugs

Joeri Exelmans 4 سال پیش
والد
کامیت
e39be44362

+ 15 - 9
lib/versioning/History.js

@@ -101,13 +101,15 @@ class History {
     };
   }
 
-  _exec(op, setState) {
-    // update mapping to point to op
+  _update_head(op) {
     for (const [key, {value}] of op.detail.entries()) {
-      this.heads.set(key, op); // update HEAD ptr
-      if (setState) {
-        this.setState(key, value);
-      }
+      this.heads.set(key, op);
+    }
+  }
+
+  _update_state(op) {
+    for (const [key, {value}] of op.detail.entries()) {
+      this.setState(key, value);
     }
   }
 
@@ -128,7 +130,7 @@ class History {
 
   // To be called when a new user operation has happened locally.
   // The new operation advances HEADs.
-  new(v, setState=true) {
+  new(v, updateState=true) {
     const newId = uuidv4();
     const detail = new Map(Object.entries(v).map(([key,value]) => {
       const {op: parent, depth} = this._getHead(key);
@@ -142,7 +144,10 @@ class History {
     for (const [key, {parent}] of detail.entries()) {
       this._setChild(parent, key, newOp);
     }
-    this._exec(newOp, setState);
+    this._update_head(newOp);
+    if (updateState) {
+      this._update_state(newOp);
+    }
 
     this.context.ops.set(newId, Promise.resolve(newOp));
     this.ops.set(newId, newOp);
@@ -212,7 +217,8 @@ class History {
     }
 
     if (exec) {
-      this._exec(op, true);
+      this._update_head(op);
+      this._update_state(op);
     }
 
     this.ops.set(op.id, op);

+ 3 - 3
lib/versioning/client.js

@@ -1,5 +1,5 @@
 /*
-Date: Wed Oct 20 12:12:58 2021
+Date: Fri Oct 22 13:09:20 2021
 
 Model author: Joeri Exelmans
 Model name: client
@@ -576,7 +576,7 @@ Main.prototype.PSocketRegionConnectingOrConnectedConnectingEnter = function() {
 };
 
 Main.prototype.PSocketRegionConnectingOrConnectedConnectedConnectionMonitorRegionAllGoodSendPingsWaitingEnter = function() {
-    this.addTimer(1, 500);
+    this.addTimer(1, 1);
 };
 
 Main.prototype.PSocketRegionConnectingOrConnectedConnectedConnectionMonitorRegionAllGoodSendPingsWaitingExit = function() {
@@ -584,7 +584,7 @@ Main.prototype.PSocketRegionConnectingOrConnectedConnectedConnectionMonitorRegio
 };
 
 Main.prototype.PSocketRegionConnectingOrConnectedConnectedConnectionMonitorRegionAllGoodReceivePongsWaitingEnter = function() {
-    this.addTimer(2, 7000);
+    this.addTimer(2, 5);
 };
 
 Main.prototype.PSocketRegionConnectingOrConnectedConnectedConnectionMonitorRegionAllGoodReceivePongsWaitingExit = function() {

+ 2 - 2
lib/versioning/client.xml

@@ -420,7 +420,7 @@
                       <!-- reset ping timer each time we send anything -->
                       <transition event="send" port="in" target="."/>
                       <!-- when not having sent anything for 1s, send a ping to let server know we're still alive -->
-                      <transition after="500" target=".">
+                      <transition after="1" target=".">
                         <script>
                           this.socket.send(JSON.stringify({type:"ping"}));
                         </script>
@@ -432,7 +432,7 @@
                       <!-- reset pong timer each time we receive anything -->
                       <transition event="message" port="socket" target="."/>
                       <!-- when not having received anything for 3s, decide the server and/or connection are (temporarily) dead -->
-                      <transition after="7000" target=".">
+                      <transition after="5" target=".">
                         <!-- WORKAROUND: for some reason, target cannot be '../../../timeout' (limitation of 'main' SCCD, fixed in 'joeri' branch), so we generate an internal event to make the transition from higher up -->
                         <raise event="timeout"/>
                       </transition>

+ 15 - 15
src/main/webapp/plugins/cdf/ftgpm-edit.js

@@ -43,7 +43,7 @@ Draw.loadPlugin(function(ui) {
     const model = ui.editor.graph.model;
 
     function setStyle(style_type) {
-      console.log("SET STYLE", style_type)
+      // console.log("SET STYLE", style_type)
 
       // Set 'pmRole' property
       let value = model.getValue(edge);
@@ -63,7 +63,7 @@ Draw.loadPlugin(function(ui) {
         "entryX", "entryY", "entryDx", "entryDy",
         "exitX",  "exitY",  "exitDx",  "exitDy"
       ]);
-      console.log((newstyle))
+      // console.log((newstyle))
       model.setStyle(edge, unparseStyle(newstyle));
     }
 
@@ -186,7 +186,7 @@ Draw.loadPlugin(function(ui) {
       const targetType = targetCell.getAttribute("pmRole");
 
       function reverseEdge() {
-        console.log("REVERSE");
+        // console.log("REVERSE");
 
         // Reverse source and target
         ui.editor.graph.model.setTerminals(edge, targetCell, sourceCell);
@@ -307,14 +307,14 @@ Draw.loadPlugin(function(ui) {
 
     ui.editor.graph.addListener(mxEvent.MOVE_CELLS, (_, eventObj) => {
       // High-level event: Happens when the user releases a dragged shape
-      console.log("MOVE_CELLS:", eventObj);
+      // console.log("MOVE_CELLS:", eventObj);
 
       snapPortsToBorder(eventObj.properties.cells);
     });
 
     ui.editor.graph.addListener(mxEvent.RESIZE_CELLS, (_, eventObj) => {
-      console.log("RESIZE");
-      console.log("EVENT:", eventObj);
+      // console.log("RESIZE");
+      // console.log("EVENT:", eventObj);
 
       // If a port is resized, re-attach:
       snapPortsToBorder(eventObj.properties.cells);
@@ -357,15 +357,15 @@ Draw.loadPlugin(function(ui) {
       }
     })
 
-    ui.editor.undoManager.addListener(null, (_, eventObj) => {
-      // For debugging:
-      console.log("UNDO:", eventObj);
-    });
+    // ui.editor.undoManager.addListener(null, (_, eventObj) => {
+    //   // For debugging:
+    //   // console.log("UNDO:", eventObj);
+    // });
 
-    ui.editor.graph.addListener(null, (_, eventObj) => {
-      if (eventObj.name !== 'fireMouseEvent')
-        console.log("GRAPH EVENT:", eventObj);
-    });
+    // ui.editor.graph.addListener(null, (_, eventObj) => {
+    //   if (eventObj.name !== 'fireMouseEvent')
+    //     console.log("GRAPH EVENT:", eventObj);
+    // });
 
     ui.loadLibrary(new LocalLibrary(ui, portsExamplesLib, "FTG+PM with ports: Examples"));
     ui.loadLibrary(new LocalLibrary(ui, portsPrimitivesLib, "FTG+PM with ports: Primitives"));
@@ -373,7 +373,7 @@ Draw.loadPlugin(function(ui) {
     console.log("Activated FTG+PM with ports")
   }
 
-  if (version === 'noports' || !version) {
+  if (version === 'noports') {
     ui.editor.graph.addListener(mxEvent.CELL_CONNECTED, (_, eventObj) => {
       function isControlFlowNode(type) {
         return type === "initial" || type === "final" || type === "fork_join" || type === "decision" || isActivityNode(type);

+ 76 - 33
src/main/webapp/plugins/cdf/versioning.browser.js

@@ -1105,13 +1105,15 @@ class History {
     };
   }
 
-  _exec(op, setState) {
-    // update mapping to point to op
+  _update_head(op) {
     for (const [key, {value}] of op.detail.entries()) {
-      this.heads.set(key, op); // update HEAD ptr
-      if (setState) {
-        this.setState(key, value);
-      }
+      this.heads.set(key, op);
+    }
+  }
+
+  _update_state(op) {
+    for (const [key, {value}] of op.detail.entries()) {
+      this.setState(key, value);
     }
   }
 
@@ -1132,7 +1134,7 @@ class History {
 
   // To be called when a new user operation has happened locally.
   // The new operation advances HEADs.
-  new(v, setState=true) {
+  new(v, updateState=true) {
     const newId = uuidv4();
     const detail = new Map(Object.entries(v).map(([key,value]) => {
       const {op: parent, depth} = this._getHead(key);
@@ -1146,7 +1148,10 @@ class History {
     for (const [key, {parent}] of detail.entries()) {
       this._setChild(parent, key, newOp);
     }
-    this._exec(newOp, setState);
+    this._update_head(newOp);
+    if (updateState) {
+      this._update_state(newOp);
+    }
 
     this.context.ops.set(newId, Promise.resolve(newOp));
     this.ops.set(newId, newOp);
@@ -1216,7 +1221,8 @@ class History {
     }
 
     if (exec) {
-      this._exec(op, true);
+      this._update_head(op);
+      this._update_state(op);
     }
 
     this.ops.set(op.id, op);
@@ -1514,31 +1520,45 @@ Draw.loadPlugin(async function(ui) {
           model.setStyle(cell, style);
         },
         parent: () => {
-          const cellId = value;
-          const parent = model.cells[cellId];
-          // The following appears to create a mxChildChange object, indicating that it is this the correct way to set the parent...
-          if (parent) {
-            model.add(parent, cell, null);
-          } else {
+          const {parentId} = value;
+          if (parentId === null) {
+            // Creates a mxChildChange object
             model.remove(cell);
           }
+          else {
+            let parent = getCell(parentId);
+            if (parent === undefined) {
+              console.log("creating non-existing parent");
+              const {isVertex, isEdge} = value;
+              parent = createCell(parentId, isVertex, isEdge);
+            }
+            // Creates a mxChildChange object
+            model.add(parent, cell, null);
+          }
         },
         value: () => {
           let v;
           if (typeof value === 'object') {
             const {xmlEncoded} = value;
-            v = xmlParser.parseFromString(xmlEncoded, 'text/xml');
+            v = xmlParser.parseFromString(xmlEncoded, 'text/xml').documentElement;
           } else {
             v = value;
           }
-          model.setValue(cell, v.documentElement);
+          model.setValue(cell, v);
         },
         source: () => {
           const sourceId = value;
           if (sourceId === null) {
             model.setTerminal(cell, null, true);
           } else {
-            const source = getCell(sourceId);
+            const source = getCell(sourceId)
+              // if in the same user operation, a vertex is created and an edge
+              // is connected to that vertex, it is possible that the connection
+              // is made before the vertex is created (operations within a single user
+              // operation are currently unordered)
+              || createCell(sourceId,
+                            /* isVertex */ true,
+                            /* isEdge */ false);
             if (source === undefined) {
               throw new Error("NO SUCH CELL:", cellId);
             }
@@ -1550,7 +1570,10 @@ Draw.loadPlugin(async function(ui) {
           if (targetId === null) {
             model.setTerminal(cell, null, false);
           } else {
-            const target = getCell(targetId);
+            const target = getCell(targetId)
+              || createCell(targetId,
+                            /* isVertex */ true,
+                            /* isEdge */ false);
             if (target === undefined) {
               throw new Error("NO SUCH CELL:", cellId);
             }
@@ -1751,7 +1774,11 @@ Draw.loadPlugin(async function(ui) {
       deltaObj[prefix + 'style'] = cell.style;
     }
     if (cell.parent) {
-      deltaObj[prefix + 'parent'] = cell.parent.id;
+      deltaObj[prefix + 'parent'] = {
+        parentId: cell.parent.id,
+        isVertex: cell.parent.isVertex(),
+        isEdge: cell.parent.isEdge(),
+      };
     }
     if (cell.value) {
       // For some reason, 'value' can be an HTML string (when only a label is defined, or it can be a DOM object
@@ -1793,6 +1820,7 @@ Draw.loadPlugin(async function(ui) {
     }
     else {
       if (change.constructor === mxGeometryChange) {
+        console.log(change.cell.id, 'change geometry')
         deltaObj[keyPrefix(change.cell) + 'geometry'] = change.geometry ?
           xmlSerializer.serializeToString(
             codec.encode(change.geometry)) : null;
@@ -1801,14 +1829,29 @@ Draw.loadPlugin(async function(ui) {
         deltaObj[keyPrefix(change.cell) + 'style'] = change.style;
       }
       else if (change.constructor === mxChildChange) {
+        console.log(change.child.id, 'change parent')
         if (change.previous && model.contains(change.previous)) {
           // cell had a previous parent
           console.log("previous parent");
-          deltaObj[keyPrefix(change.child) + 'parent'] = change.parent ? change.parent.id: null;
+          deltaObj[keyPrefix(change.child) + 'parent'] = change.parent ? {
+            parentId: change.parent.id,
+            isVertex: change.parent.isVertex(),
+            isEdge: change.parent.isEdge(),
+          } : {
+            parentId: null,
+          };
         } else {
           // no previous parent -> cell was created:
           console.log("no previous parent");
-          encodeCompleteCellState(change.child, deltaObj);
+          function recursivelyEncode(cell) {
+            encodeCompleteCellState(cell, deltaObj);
+            if (cell.children !== null) {
+              for (const child of cell.children) {
+                recursivelyEncode(child);
+              }
+            }
+          }
+          recursivelyEncode(change.child);
         }
       }
       else if (change.constructor === mxValueChange) {
@@ -1861,18 +1904,18 @@ Draw.loadPlugin(async function(ui) {
   // UI stuff
   uiState.install(ui);
 
-  // document.addEventListener('keydown', e => {
+  document.addEventListener('keydown', e => {
   //   console.log(e);
-  //   if (e.code === 'KeyC') {
-  //     console.log("KeyC pressed: Clear model and reset history");
-  //     resetHistory();
-  //     model.clear();
-  //   }
+    if (e.code === 'KeyC') {
+      console.log("KeyC pressed: Clear model and reset history");
+      resetHistory();
+      model.clear();
+    }
 
-  //   if (e.code === 'KeyH') {
-  //     const seq = history.getOpsSequence();
-  //     console.log(seq.map(op => op.serialize()));
-  //   }
+    if (e.code === 'KeyH') {
+      const seq = history.getOpsSequence();
+      console.log(seq.map(op => op.serialize()));
+    }
 
   //   if (e.code === 'KeyU') {
   //     const u = window.prompt("Choose a user name:", myName);
@@ -1880,6 +1923,6 @@ Draw.loadPlugin(async function(ui) {
   //       myName = u;
   //     }
   //   }
-  // })
+  });
 });
 },{"../../../../../lib/versioning/DragHandler.js":16,"../../../../../lib/versioning/GhostOverlays.js":17,"../../../../../lib/versioning/History.js":18,"../../../../../lib/versioning/UserColors.js":19}]},{},[20]);

+ 61 - 24
src/main/webapp/plugins/cdf/versioning.js

@@ -238,31 +238,45 @@ Draw.loadPlugin(async function(ui) {
           model.setStyle(cell, style);
         },
         parent: () => {
-          const cellId = value;
-          const parent = model.cells[cellId];
-          // The following appears to create a mxChildChange object, indicating that it is this the correct way to set the parent...
-          if (parent) {
-            model.add(parent, cell, null);
-          } else {
+          const {parentId} = value;
+          if (parentId === null) {
+            // Creates a mxChildChange object
             model.remove(cell);
           }
+          else {
+            let parent = getCell(parentId);
+            if (parent === undefined) {
+              console.log("creating non-existing parent");
+              const {isVertex, isEdge} = value;
+              parent = createCell(parentId, isVertex, isEdge);
+            }
+            // Creates a mxChildChange object
+            model.add(parent, cell, null);
+          }
         },
         value: () => {
           let v;
           if (typeof value === 'object') {
             const {xmlEncoded} = value;
-            v = xmlParser.parseFromString(xmlEncoded, 'text/xml');
+            v = xmlParser.parseFromString(xmlEncoded, 'text/xml').documentElement;
           } else {
             v = value;
           }
-          model.setValue(cell, v.documentElement);
+          model.setValue(cell, v);
         },
         source: () => {
           const sourceId = value;
           if (sourceId === null) {
             model.setTerminal(cell, null, true);
           } else {
-            const source = getCell(sourceId);
+            const source = getCell(sourceId)
+              // if in the same user operation, a vertex is created and an edge
+              // is connected to that vertex, it is possible that the connection
+              // is made before the vertex is created (operations within a single user
+              // operation are currently unordered)
+              || createCell(sourceId,
+                            /* isVertex */ true,
+                            /* isEdge */ false);
             if (source === undefined) {
               throw new Error("NO SUCH CELL:", cellId);
             }
@@ -274,7 +288,10 @@ Draw.loadPlugin(async function(ui) {
           if (targetId === null) {
             model.setTerminal(cell, null, false);
           } else {
-            const target = getCell(targetId);
+            const target = getCell(targetId)
+              || createCell(targetId,
+                            /* isVertex */ true,
+                            /* isEdge */ false);
             if (target === undefined) {
               throw new Error("NO SUCH CELL:", cellId);
             }
@@ -475,7 +492,11 @@ Draw.loadPlugin(async function(ui) {
       deltaObj[prefix + 'style'] = cell.style;
     }
     if (cell.parent) {
-      deltaObj[prefix + 'parent'] = cell.parent.id;
+      deltaObj[prefix + 'parent'] = {
+        parentId: cell.parent.id,
+        isVertex: cell.parent.isVertex(),
+        isEdge: cell.parent.isEdge(),
+      };
     }
     if (cell.value) {
       // For some reason, 'value' can be an HTML string (when only a label is defined, or it can be a DOM object
@@ -517,6 +538,7 @@ Draw.loadPlugin(async function(ui) {
     }
     else {
       if (change.constructor === mxGeometryChange) {
+        console.log(change.cell.id, 'change geometry')
         deltaObj[keyPrefix(change.cell) + 'geometry'] = change.geometry ?
           xmlSerializer.serializeToString(
             codec.encode(change.geometry)) : null;
@@ -525,14 +547,29 @@ Draw.loadPlugin(async function(ui) {
         deltaObj[keyPrefix(change.cell) + 'style'] = change.style;
       }
       else if (change.constructor === mxChildChange) {
+        console.log(change.child.id, 'change parent')
         if (change.previous && model.contains(change.previous)) {
           // cell had a previous parent
           console.log("previous parent");
-          deltaObj[keyPrefix(change.child) + 'parent'] = change.parent ? change.parent.id: null;
+          deltaObj[keyPrefix(change.child) + 'parent'] = change.parent ? {
+            parentId: change.parent.id,
+            isVertex: change.parent.isVertex(),
+            isEdge: change.parent.isEdge(),
+          } : {
+            parentId: null,
+          };
         } else {
           // no previous parent -> cell was created:
           console.log("no previous parent");
-          encodeCompleteCellState(change.child, deltaObj);
+          function recursivelyEncode(cell) {
+            encodeCompleteCellState(cell, deltaObj);
+            if (cell.children !== null) {
+              for (const child of cell.children) {
+                recursivelyEncode(child);
+              }
+            }
+          }
+          recursivelyEncode(change.child);
         }
       }
       else if (change.constructor === mxValueChange) {
@@ -585,18 +622,18 @@ Draw.loadPlugin(async function(ui) {
   // UI stuff
   uiState.install(ui);
 
-  // document.addEventListener('keydown', e => {
+  document.addEventListener('keydown', e => {
   //   console.log(e);
-  //   if (e.code === 'KeyC') {
-  //     console.log("KeyC pressed: Clear model and reset history");
-  //     resetHistory();
-  //     model.clear();
-  //   }
+    if (e.code === 'KeyC') {
+      console.log("KeyC pressed: Clear model and reset history");
+      resetHistory();
+      model.clear();
+    }
 
-  //   if (e.code === 'KeyH') {
-  //     const seq = history.getOpsSequence();
-  //     console.log(seq.map(op => op.serialize()));
-  //   }
+    if (e.code === 'KeyH') {
+      const seq = history.getOpsSequence();
+      console.log(seq.map(op => op.serialize()));
+    }
 
   //   if (e.code === 'KeyU') {
   //     const u = window.prompt("Choose a user name:", myName);
@@ -604,5 +641,5 @@ Draw.loadPlugin(async function(ui) {
   //       myName = u;
   //     }
   //   }
-  // })
+  });
 });