|
|
@@ -70,12 +70,12 @@ Draw.loadPlugin(function(ui) {
|
|
|
if (!sourceCell || !targetCell) {
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
const sourceType = sourceCell.getAttribute("pmRole");
|
|
|
const targetType = targetCell.getAttribute("pmRole");
|
|
|
|
|
|
- for (const [from, to, linkType] of fromTo) {
|
|
|
- if (from(sourceType) && to(targetType)) {
|
|
|
+ for (const [cond, linkType] of fromTo) {
|
|
|
+ if (cond(sourceType, targetType)) {
|
|
|
setStyle(linkType);
|
|
|
}
|
|
|
}
|
|
|
@@ -120,6 +120,8 @@ Draw.loadPlugin(function(ui) {
|
|
|
ui.editor.graph.addListener(mxEvent.CELL_CONNECTED, (_, eventObj) => {
|
|
|
// Happens whenever an edge is (dis)connected.
|
|
|
|
|
|
+ const edge = eventObj.properties.edge;
|
|
|
+
|
|
|
// This will change the edge style WITHIN the transaction of the edit operation.
|
|
|
// The terminal-change and style-change will be one edit operation from point of view of undo manager.
|
|
|
|
|
|
@@ -129,6 +131,12 @@ Draw.loadPlugin(function(ui) {
|
|
|
function isDataPort(type) {
|
|
|
return type === "data_in" || type === "data_out";
|
|
|
}
|
|
|
+ function isInport(type) {
|
|
|
+ return type === "data_in" || type === "ctrl_in";
|
|
|
+ }
|
|
|
+ function isOutport(type) {
|
|
|
+ return type === "data_out" || type === "ctrl_out";
|
|
|
+ }
|
|
|
function isControlFlowNode(type) {
|
|
|
return isControlFlowPort(type) || type === "initial" || type === "final" || type === "fork_join";
|
|
|
}
|
|
|
@@ -136,21 +144,38 @@ Draw.loadPlugin(function(ui) {
|
|
|
return isDataPort(type) || isArtifact(type);
|
|
|
}
|
|
|
|
|
|
- // [ from, to, style ]
|
|
|
+ // [ condition, style ]
|
|
|
const fromTo = [
|
|
|
// PM control flow
|
|
|
- [ isControlFlowNode, isControlFlowNode, "control_flow" ],
|
|
|
+ [ (src, tgt) => isControlFlowNode(src) && isControlFlowNode(tgt), "control_flow" ],
|
|
|
|
|
|
// PM data flow
|
|
|
- [ isDataFlowNode, isDataFlowNode, "data_flow" ],
|
|
|
+ [ (src, tgt) => isDataFlowNode(src) && isDataFlowNode(tgt), "data_flow" ],
|
|
|
|
|
|
// FTG data flow
|
|
|
- [ isTransformation, isFormalism, "data_flow" ],
|
|
|
- [ isFormalism, isTransformation, "data_flow" ],
|
|
|
+ [ (src, tgt) => isTransformation(src) && isFormalism(tgt), "data_flow" ],
|
|
|
+ [ (src, tgt) => isFormalism(src) && isTransformation(tgt), "data_flow" ],
|
|
|
|
|
|
].concat(typedByLinks);
|
|
|
|
|
|
- checkEdge(ui, eventObj.properties.edge, fromTo);
|
|
|
+ // Update style
|
|
|
+ checkEdge(ui, edge, fromTo);
|
|
|
+
|
|
|
+ // Reverse direction, if necessary
|
|
|
+ const sourceCell = edge.source;
|
|
|
+ const targetCell = edge.getTerminal();
|
|
|
+
|
|
|
+ if (!sourceCell || !targetCell) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const sourceType = sourceCell.getAttribute("pmRole");
|
|
|
+ const targetType = targetCell.getAttribute("pmRole");
|
|
|
+ if (isInport(sourceType) && isOutport(targetType)) {
|
|
|
+ console.log("REVERSE");
|
|
|
+
|
|
|
+ ui.editor.graph.model.setTerminals(edge, targetCell, sourceCell); // swap
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
const portClasses = [ "data_in", "data_out", "ctrl_in", "ctrl_out", ];
|
|
|
@@ -261,10 +286,10 @@ Draw.loadPlugin(function(ui) {
|
|
|
reversePortMapping.set(cell, cell.parent);
|
|
|
}
|
|
|
|
|
|
- function findPortsAndAttach(cells) {
|
|
|
+ function findPortsAndAttach(cells, moveCells) {
|
|
|
for (const cell of cells) {
|
|
|
if (cell.parent && cell.parent.geometry && isPort(cell.getAttribute("pmRole"))) {
|
|
|
- attachPortToParent(cell, true);
|
|
|
+ attachPortToParent(cell, moveCells);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -273,13 +298,17 @@ Draw.loadPlugin(function(ui) {
|
|
|
// console.log("MOVE_CELLS:", eventObj);
|
|
|
|
|
|
// High-level event: Happens when the user releases a dragged shape
|
|
|
- findPortsAndAttach(eventObj.properties.cells);
|
|
|
+ findPortsAndAttach(eventObj.properties.cells, true);
|
|
|
})
|
|
|
|
|
|
ui.editor.graph.addListener(mxEvent.RESIZE_CELLS, (_, eventObj) => {
|
|
|
console.log("RESIZE");
|
|
|
console.log("EVENT:", eventObj);
|
|
|
|
|
|
+ // Resized shapes might contain ports:
|
|
|
+ findPortsAndAttach(eventObj.properties.cells, true);
|
|
|
+
|
|
|
+ // Move contained ports
|
|
|
for (const parent of eventObj.properties.cells) {
|
|
|
if (!parent.geometry) continue;
|
|
|
const portList = portMapping.get(parent);
|
|
|
@@ -309,7 +338,10 @@ Draw.loadPlugin(function(ui) {
|
|
|
console.log("GRAPH EVENT:", eventObj);
|
|
|
|
|
|
// Root has changed (new model loaded)
|
|
|
- findPortsAndAttach(Object.values(ui.editor.graph.model.cells));
|
|
|
+ findPortsAndAttach(
|
|
|
+ Object.values(ui.editor.graph.model.cells),
|
|
|
+ false, // only initialize portMapping and reversePortMapping - do not move cells when loading.
|
|
|
+ );
|
|
|
});
|
|
|
|
|
|
window.ui = ui;
|
|
|
@@ -326,21 +358,23 @@ Draw.loadPlugin(function(ui) {
|
|
|
return type === "initial" || type === "final" || type === "fork_join" || type === "decision" || isActivityNode(type);
|
|
|
}
|
|
|
|
|
|
+ const edge = eventObj.properties.edge;
|
|
|
+
|
|
|
const fromTo = [
|
|
|
// PM control flow
|
|
|
- [ isControlFlowNode, isControlFlowNode, "control_flow" ],
|
|
|
+ [ (src, tgt) => isControlFlowNode(src) && isControlFlowNode(tgt), "control_flow" ],
|
|
|
|
|
|
// PM data flow
|
|
|
- [ isActivityNode, isArtifact, "data_flow" ],
|
|
|
- [ isArtifact, isActivityNode, "data_flow" ],
|
|
|
+ [ (src, tgt) => isActivityNode(src) && isArtifact(tgt), "data_flow" ],
|
|
|
+ [ (src, tgt) => isArtifact(src) && isActivityNode(tgt), "data_flow" ],
|
|
|
|
|
|
// FTG data flow
|
|
|
- [ isTransformation, isFormalism, "data_flow" ],
|
|
|
- [ isFormalism, isTransformation, "data_flow" ],
|
|
|
+ [ (src, tgt) => isTransformation(src) && isFormalism(tgt), "data_flow" ],
|
|
|
+ [ (src, tgt) => isFormalism(src) && isTransformation(tgt), "data_flow" ],
|
|
|
|
|
|
].concat(typedByLinks);
|
|
|
|
|
|
- checkEdge(ui, eventObj.properties.edge, fromTo);
|
|
|
+ checkEdge(ui, edge, fromTo);
|
|
|
});
|
|
|
|
|
|
ui.loadLibrary(new LocalLibrary(ui, noportsExamplesLib, "FTG+PM: Examples"));
|