diff --git a/com.actionsoft.apps.coe.method.process.subprocess/lib/com.actionsoft.apps.coe.method.process.subprocess.jar b/com.actionsoft.apps.coe.method.process.subprocess/lib/com.actionsoft.apps.coe.method.process.subprocess.jar index 61a12eb6..34bf9184 100644 Binary files a/com.actionsoft.apps.coe.method.process.subprocess/lib/com.actionsoft.apps.coe.method.process.subprocess.jar and b/com.actionsoft.apps.coe.method.process.subprocess/lib/com.actionsoft.apps.coe.method.process.subprocess.jar differ diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphNodeCloseHandle.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphNodeCloseHandle.java index a4398c04..3230a2c3 100644 --- a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphNodeCloseHandle.java +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphNodeCloseHandle.java @@ -7,6 +7,7 @@ import com.actionsoft.apps.coe.method.process.subprocess.graph.component.Abstrac import com.actionsoft.apps.coe.method.process.subprocess.graph.util.DefinitionThreadUnSafe; import com.actionsoft.apps.coe.method.process.subprocess.graph.util.SubProcessNodeDefineUtil; import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor; +import com.actionsoft.apps.coe.method.process.subprocess.observers.node.NodeSubject; import com.actionsoft.apps.coe.pal.pal.repository.cache.PALRepositoryCache; import com.actionsoft.apps.coe.pal.pal.repository.designer.manage.CoeDesignerAPIManager; import com.actionsoft.apps.coe.pal.pal.repository.designer.model.BaseModel; @@ -36,6 +37,7 @@ public class GraphNodeCloseHandle { private AbstractDefinitionHandle definitionHandle; // 当前总图 define 处理器 private AbstractDefinitionHandle subProcessNodeDefineHandle; // 子流程节点 define 处理器 private ScopeShapeMonitor scopeShapeMonitor; // 范围选择框及其内部元素监视器 + private NodeSubject nodeSubject; // 当前操作的节点主题类 public GraphNodeCloseHandle(String repositoryId, String shapeId, String endToEndProcessDefineStr) throws AWSException{ this.repositoryId = repositoryId; @@ -54,6 +56,10 @@ public class GraphNodeCloseHandle { scopeLimitationShape = definitionHandle.getShapeByKey(shapeId); scopeShapeMonitor = new ScopeShapeMonitor(definitionHandle); + scopeShapeMonitor.buildScopeShapeMonitors(); + + nodeSubject = new NodeSubject(definitionHandle, scopeShapeMonitor, shapeId, "close"); + nodeSubject.buildObservers(); } catch (AWSException e) { throw new AWSException(e); @@ -71,8 +77,6 @@ public class GraphNodeCloseHandle { // 1、处理范围选择框及其内部节点 removeScopeShapeAndInRangeEle(); - scopeShapeMonitor.buildScopeShapeMonitors(); - // 2、处理总图中的节点与连线 handleEndToEndGraphNodeAndLinker(); @@ -85,6 +89,11 @@ public class GraphNodeCloseHandle { // 1、创建对应子流程节点 JSONObject subProcessNode = buildSubProcessNode(shapeId, scopeLimitationShape); definitionHandle.addEle(shapeId, subProcessNode); + + // 通知其它节点位置更新 + nodeSubject.setScopeW(subProcessNode.getJSONObject("props").getDoubleValue("w")); + nodeSubject.setScopeH(subProcessNode.getJSONObject("props").getDoubleValue("h")); + // 2、根据现有连线关系创建邻接矩阵 NodeCloseAdjMatrix closeAdjMatrix = buildEndToEndGraphAdjMatrix(); closeAdjMatrix.buildAdjMatrix(); @@ -92,13 +101,13 @@ public class GraphNodeCloseHandle { JSONObject elements = definitionHandle.getElements(); // 更新因节点展开后 坐标发生变化的节点坐标 String direction = definitionHandle.getProcessProperties().getString("direction"); - graphPartNodePoiRenderAgain(elements, direction, subProcessNode); + // graphPartNodePoiRenderAgain(elements, direction, subProcessNode); // 3、收集现有元素坐标 double[][] vertexBounding = closeAdjMatrix.getVertexBounding(elements); // 4、删除现有连线 removeEndToEndGraphOldLinker(); // 5、构建新的连线 - NodeCloseLinkerRender linkerRender = new NodeCloseLinkerRender(vertexBounding, closeAdjMatrix); + NodeCloseLinkerRender linkerRender = new NodeCloseLinkerRender(vertexBounding, closeAdjMatrix, definitionHandle); JSONArray linkers = linkerRender.toAssembleLinker(direction); for (Object o : linkers) { JSONObject linker = (JSONObject) o; @@ -305,6 +314,8 @@ public class GraphNodeCloseHandle { } definitionHandle.removeShape(shapeId); + + scopeShapeMonitor.removeScopeShapeByKey(shapeId); } } @@ -374,11 +385,13 @@ class NodeCloseLinkerRender{ private List nodeIds; // 图形节点ID集合 private double[][] vertexPosition; // 所有节点的坐标 private NodeCloseAdjMatrix closeAdjMatrix; // 节点矩阵 + private AbstractDefinitionHandle definitionHandle; - public NodeCloseLinkerRender(double[][] vertexPosition, NodeCloseAdjMatrix closeAdjMatrix) { + public NodeCloseLinkerRender(double[][] vertexPosition, NodeCloseAdjMatrix closeAdjMatrix, AbstractDefinitionHandle definitionHandle) { this.nodeIds = closeAdjMatrix.getNodeIds(); this.vertexPosition = vertexPosition; this.closeAdjMatrix = closeAdjMatrix; + this.definitionHandle = definitionHandle; } /** @@ -451,38 +464,38 @@ class NodeCloseLinkerRender{ return fromY < toY ? new double[][]{ startPoi, - {fromX + fromW / 2, fromY + fromH + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, endPoi} : new double[][]{ startPoi, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, endPoi}; }else { // 分布在四个象限内 if (fromX > toX && fromY > toY){ // 目标节点在第二象限 return new double[][]{ {fromX + fromW, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY} }; }else if (fromX > toX && fromY < toY){ // 目标节点在第三象限 - return toY - fromY == SubProcessConst.SHAPE_VERT_INTERVAL + return toY - getCurrentRowMaxH(fromY) == SubProcessConst.SHAPE_VERT_INTERVAL // 相邻行节点 ? new double[][] { {fromX + fromW / 2, fromY + fromH}, - {fromX + fromW / 2, fromY + fromH + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY} } : new double[][] { {fromX + fromW / 2, fromY + fromH}, - {fromX + fromW / 2, fromY + fromH + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, - {toX + toW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {toX + toW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + getCurrentRowMaxH(fromY) + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY} @@ -490,7 +503,7 @@ class NodeCloseLinkerRender{ }else if (fromX < toX && fromY < toY){ // 目标节点在第四象限 return new double[][]{ {fromX + fromW / 2, fromY + fromH}, - {fromX + fromW / 2, fromY + fromH + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY} }; @@ -508,7 +521,7 @@ class NodeCloseLinkerRender{ ? new double[][] { {fromX + fromW, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, {toX - SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY + toH / 2}, {toX, toY + toH / 2} } @@ -525,15 +538,15 @@ class NodeCloseLinkerRender{ double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2}; double[] endPoint = new double[]{toX + toW / 2, toY}; return new double[][]{startPoint, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, endPoint}; }else { if (fromX < toX && fromY > toY){ // 目标节点在第一象限 double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2}; - double turnPointX = fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2; - if (fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点 + double turnPointX = fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2; + if (fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点 double[] endPoint = new double[]{toX, toY + toH / 2}; return new double[][]{startPoint,{turnPointX, fromY + fromH / 2},{turnPointX, toY + toH / 2}, endPoint}; }else { // 不相邻节点 存在三个折点 @@ -551,15 +564,15 @@ class NodeCloseLinkerRender{ double[] endPoint = new double[]{toX + toW / 2, toY}; return new double[][]{ startPoint, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, endPoint }; }else if (fromX < toX && fromY < toY){ // 目标节点在第四象限 double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2}; - if (fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点 - double turnPointX = fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2; + if (fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点 + double turnPointX = fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2; double[] endPoint = new double[]{toX, toY + toH / 2}; return new double[][]{ startPoint, @@ -571,8 +584,8 @@ class NodeCloseLinkerRender{ double[] endPoint = new double[]{toX + toW / 2, toY}; return new double[][]{ startPoint, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, endPoint }; @@ -584,6 +597,35 @@ class NodeCloseLinkerRender{ return new double[2][2]; } + /** + * 获取当前同一列图形的最大宽度 在水平布局中 + * @param fromShapeX 当前图形的 x 坐标 + * @return + */ + private double getCurrentColMaxW(double fromShapeX){ + JSONObject elements = definitionHandle.getElements(); + JSONObject props = elements.keySet().stream() + .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")) && fromShapeX == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x")) + .map(key -> elements.getJSONObject(key).getJSONObject("props")) + .max(Comparator.comparing(o -> o.getDoubleValue("w"))).get(); + return props.getDoubleValue("w"); + } + + /** + * 获取当前同一行图形的最大高度 在垂直布局中 + * @param fromShapeY + * @return + */ + private double getCurrentRowMaxH(double fromShapeY){ + JSONObject elements = definitionHandle.getElements(); + JSONObject props = elements.keySet().stream() + .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")) && fromShapeY == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y")) + .map(key -> elements.getJSONObject(key).getJSONObject("props")) + .max(Comparator.comparing(o -> o.getDoubleValue("h"))).get(); + return props.getDoubleValue("h"); + } + + /** * 计算angle值 * @param fromPoi 起始节点坐标 diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphNodeExpandHandle.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphNodeExpandHandle.java index 4fcc3adb..4929b070 100644 --- a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphNodeExpandHandle.java +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/graph/GraphNodeExpandHandle.java @@ -8,6 +8,7 @@ import com.actionsoft.apps.coe.method.process.subprocess.graph.util.DefinitionTh import com.actionsoft.apps.coe.method.process.subprocess.graph.util.SubProcessNodeDefineUtil; import com.actionsoft.apps.coe.method.process.subprocess.mode.Node; import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor; +import com.actionsoft.apps.coe.method.process.subprocess.observers.node.NodeSubject; import com.actionsoft.apps.coe.pal.pal.repository.designer.manage.CoeDesignerAPIManager; import com.actionsoft.apps.coe.pal.pal.repository.designer.model.BaseModel; import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.cache.DesignerShapeRelationCache; @@ -37,6 +38,7 @@ public class GraphNodeExpandHandle { private AbstractDefinitionHandle definitionHandle; // 当前总图 define 处理器 private AbstractDefinitionHandle subProcessNodeDefineHandle; // 子流程节点 define 处理器 private ScopeShapeMonitor scopeShapeMonitor; // 范围选择框及其内部元素监视器 + private NodeSubject nodeSubject; // 当前操作的节点主题类 private double[] scopeLimitationShapeBeforePoi; // 范围选择框在子流程文件中的坐标 @@ -54,6 +56,11 @@ public class GraphNodeExpandHandle { subProcessNodeDefineHandle = new DefinitionThreadUnSafe(SubProcessNodeDefineUtil.readSubProcessNodeDefine(repositoryId, shapeId)); scopeShapeMonitor = new ScopeShapeMonitor(definitionHandle); + // 1、构建范围框监视器模型 并关联内部元素 + scopeShapeMonitor.buildScopeShapeMonitors(); + + nodeSubject = new NodeSubject(definitionHandle, scopeShapeMonitor, shapeId, "expand"); + nodeSubject.buildObservers(); toAssembleScopeLimitationShape(); } catch (Exception e) { @@ -93,6 +100,10 @@ public class GraphNodeExpandHandle { scopeLimitationShape.put("dataAttributes", currentExpandShape.getJSONArray("dataAttributes")); this.scopeLimitationShape = scopeLimitationShape; + + // 通知其它节点位置更新 + nodeSubject.setScopeW(scope[2]); + nodeSubject.setScopeH(scope[3]); } /** @@ -103,9 +114,6 @@ public class GraphNodeExpandHandle { */ public String handleNodeExpand() throws AWSException{ - // 1、构建范围框监视器模型 并关联内部元素 - scopeShapeMonitor.buildScopeShapeMonitors(); - // 2、总图节点以及连线处理 handleEndToEndGraphNodeAndLinker(); @@ -136,7 +144,7 @@ public class GraphNodeExpandHandle { definitionHandle.addEle(shapeId, scopeLimitationShape); // 3、总图中符合范围选择框条件的节点 坐标更新 - handleEndToEndGraphNodeExcluedExpandNode(); + // handleEndToEndGraphNodeExcluedExpandNode(); // 4、构建邻接矩阵 NodeExpandAdjMatrix expandAdjMatrix = buildEndToEndGraphAdjMatrix(); @@ -150,7 +158,7 @@ public class GraphNodeExpandHandle { // 7、构建新的连线 JSONObject processProperties = definitionHandle.getProcessProperties(); String direction = processProperties.getString("direction"); - NodeExpandLinkerRender linkerRender = new NodeExpandLinkerRender(vertexBounding, expandAdjMatrix); + NodeExpandLinkerRender linkerRender = new NodeExpandLinkerRender(vertexBounding, expandAdjMatrix, definitionHandle); JSONArray linkers = linkerRender.toAssembleLinker(direction); for (Object o : linkers) { JSONObject linker = (JSONObject) o; @@ -410,14 +418,16 @@ class NodeExpandAdjMatrix extends AbstractAdjMatrix { */ class NodeExpandLinkerRender{ + private AbstractDefinitionHandle definitionHandle; // 总图 define 处理器 private List nodeIds; // 图形节点ID集合 private double[][] vertexPosition; // 所有节点的坐标以及宽高 double[][]{{x, y, w, h},{}} private NodeExpandAdjMatrix expandAdjMatrix; // 节点矩阵 - public NodeExpandLinkerRender(double[][] vertexPosition, NodeExpandAdjMatrix expandAdjMatrix) { + public NodeExpandLinkerRender(double[][] vertexPosition, NodeExpandAdjMatrix expandAdjMatrix, AbstractDefinitionHandle definitionHandle) { this.nodeIds = expandAdjMatrix.getNodeIds(); this.vertexPosition = vertexPosition; this.expandAdjMatrix = expandAdjMatrix; + this.definitionHandle = definitionHandle; } /** @@ -491,38 +501,38 @@ class NodeExpandLinkerRender{ return fromY < toY ? new double[][]{ startPoi, - {fromX + fromW / 2, fromY + fromH + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, endPoi} : new double[][]{ startPoi, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, endPoi}; }else { // 分布在四个象限内 if (fromX > toX && fromY > toY){ // 目标节点在第二象限 return new double[][]{ {fromX + fromW, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY} }; }else if (fromX > toX && fromY < toY){ // 目标节点在第三象限 - return toY - fromY == SubProcessConst.SHAPE_VERT_INTERVAL + return toY - getCurrentRowMaxH(fromY) == SubProcessConst.SHAPE_VERT_INTERVAL // 相邻行节点 ? new double[][] { {fromX + fromW / 2, fromY + fromH}, - {fromX + fromW / 2, fromY + fromH + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY} } : new double[][] { {fromX + fromW / 2, fromY + fromH}, - {fromX + fromW / 2, fromY + fromH + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, - {toX + toW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {toX + toW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + getCurrentRowMaxH(fromY) + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY} @@ -530,7 +540,7 @@ class NodeExpandLinkerRender{ }else if (fromX < toX && fromY < toY){ // 目标节点在第四象限 return new double[][]{ {fromX + fromW / 2, fromY + fromH}, - {fromX + fromW / 2, fromY + fromH + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + fromW / 2, fromY + getCurrentRowMaxH(fromY) + SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY} }; @@ -549,7 +559,7 @@ class NodeExpandLinkerRender{ ? new double[][] { {fromX + fromW, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, {toX - SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY + toH / 2}, {toX, toY + toH / 2} } @@ -566,15 +576,15 @@ class NodeExpandLinkerRender{ double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2}; double[] endPoint = new double[]{toX + toW / 2, toY}; return new double[][]{startPoint, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, endPoint}; }else { if (fromX < toX && fromY > toY){ // 目标节点在第一象限 double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2}; - double turnPointX = fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2; - if (fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点 + double turnPointX = fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2; + if (fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点 double[] endPoint = new double[]{toX, toY + toH / 2}; return new double[][]{startPoint,{turnPointX, fromY + fromH / 2},{turnPointX, toY + toH / 2}, endPoint}; }else { // 不相邻节点 存在三个折点 @@ -592,15 +602,15 @@ class NodeExpandLinkerRender{ double[] endPoint = new double[]{toX + toW / 2, toY}; return new double[][]{ startPoint, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, endPoint }; }else if (fromX < toX && fromY < toY){ // 目标节点在第四象限 double[] startPoint = new double[]{fromX + fromW, fromY + fromH / 2}; - if (fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点 - double turnPointX = fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2; + if (fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL == toX){ // 相邻节点 存在两个折点 + double turnPointX = fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2; double[] endPoint = new double[]{toX, toY + toH / 2}; return new double[][]{ startPoint, @@ -612,8 +622,8 @@ class NodeExpandLinkerRender{ double[] endPoint = new double[]{toX + toW / 2, toY}; return new double[][]{ startPoint, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, - {fromX + fromW + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, fromY + fromH / 2}, + {fromX + getCurrentColMaxW(fromX) + SubProcessConst.SHAPE_HORIZ_INTERVAL / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, {toX + toW / 2, toY - SubProcessConst.SHAPE_VERT_INTERVAL / 2}, endPoint }; @@ -625,6 +635,34 @@ class NodeExpandLinkerRender{ return new double[2][2]; } + /** + * 获取当前同一列图形的最大宽度 在水平布局中 + * @param fromShapeX 当前图形的 x 坐标 + * @return + */ + private double getCurrentColMaxW(double fromShapeX){ + JSONObject elements = definitionHandle.getElements(); + JSONObject props = elements.keySet().stream() + .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")) && fromShapeX == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x")) + .map(key -> elements.getJSONObject(key).getJSONObject("props")) + .max(Comparator.comparing(o -> o.getDoubleValue("w"))).get(); + return props.getDoubleValue("w"); + } + + /** + * 获取当前同一行图形的最大高度 在垂直布局中 + * @param fromShapeY + * @return + */ + private double getCurrentRowMaxH(double fromShapeY){ + JSONObject elements = definitionHandle.getElements(); + JSONObject props = elements.keySet().stream() + .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")) && fromShapeY == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y")) + .map(key -> elements.getJSONObject(key).getJSONObject("props")) + .max(Comparator.comparing(o -> o.getDoubleValue("h"))).get(); + return props.getDoubleValue("h"); + } + /** * 计算angle值 * @param fromPoi 起始节点坐标 diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/mode/ScopeShapeMonitor.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/mode/ScopeShapeMonitor.java index e06daead..c13ed59f 100644 --- a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/mode/ScopeShapeMonitor.java +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/mode/ScopeShapeMonitor.java @@ -71,6 +71,12 @@ public class ScopeShapeMonitor { return scopeShapeMonitorMap; } + public void removeScopeShapeByKey(String scopeShapeId){ + if (scopeShapeMonitorMap.containsKey(scopeShapeId)){ + scopeShapeMonitorMap.remove(scopeShapeId); + } + } + /** * 更新范围框的监视属性信息 * @param scopeShapeId 当前范围框图形ID diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/Observer.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/Observer.java new file mode 100644 index 00000000..9f155474 --- /dev/null +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/Observer.java @@ -0,0 +1,11 @@ +package com.actionsoft.apps.coe.method.process.subprocess.observers; + +/** + * @author oYang + * @Description 观察者接口 + * @createTime 2023年06月16日 09:37:00 + */ +public interface Observer { + + void update(double deltaX, double deltaY); +} diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/Subject.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/Subject.java new file mode 100644 index 00000000..123bce26 --- /dev/null +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/Subject.java @@ -0,0 +1,22 @@ +package com.actionsoft.apps.coe.method.process.subprocess.observers; + +/** + * @author oYang + * @Description 主题接口 + * @createTime 2023年06月16日 09:45:00 + */ +public interface Subject { + + void addRightNodeObserver(Observer o); + + void addBottomNodeObserver(Observer o); + + void removeRightObserver(Observer o); + + void removeBottomObserver(Observer o); + + void notifyRightObservers(double deltaX, double deltaY); + + void notifyBottomObservers(double deltaX, double deltaY); + +} diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/node/NodeObserver.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/node/NodeObserver.java new file mode 100644 index 00000000..8fc5721a --- /dev/null +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/node/NodeObserver.java @@ -0,0 +1,40 @@ +package com.actionsoft.apps.coe.method.process.subprocess.observers.node; + +import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; +import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor; +import com.actionsoft.apps.coe.method.process.subprocess.observers.Observer; +import com.alibaba.fastjson.JSONObject; + +/** + * @author oYang + * @Description 画布中除当前操作节点外 其它的节点观察者类 当前的操作节点的宽度与高度发生变化时 其它的观察者节点位置根据增量调整 + * @createTime 2023年06月16日 10:23:00 + */ +public class NodeObserver implements Observer { + + private AbstractDefinitionHandle definitionHandle; + private ScopeShapeMonitor scopeShapeMonitor; // 总图目前已存在的范围框监视模型 + private String nodeKey; // 画布中的节点元素的Id + + public NodeObserver(AbstractDefinitionHandle definitionHandle, ScopeShapeMonitor scopeShapeMonitor, String nodeKey) { + this.definitionHandle = definitionHandle; + this.scopeShapeMonitor = scopeShapeMonitor; + this.nodeKey = nodeKey; + } + + @Override + public void update(double deltaX, double deltaY) { + if (deltaX != 0) { + definitionHandle.updateShapeX(nodeKey, definitionHandle.getShapeX(nodeKey) + deltaX); + if (scopeShapeMonitor.checkShapeIsScopeShape(nodeKey)){ + scopeShapeMonitor.updateMonitorXInfo(nodeKey, true, deltaX); + } + } + if (deltaY != 0) { + definitionHandle.updateShapeY(nodeKey, definitionHandle.getShapeY(nodeKey) + deltaY); + if (scopeShapeMonitor.checkShapeIsScopeShape(nodeKey)){ + scopeShapeMonitor.updateMonitorYInfo(nodeKey, true, deltaY); + } + } + } +} diff --git a/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/node/NodeSubject.java b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/node/NodeSubject.java new file mode 100644 index 00000000..44df489d --- /dev/null +++ b/com.actionsoft.apps.coe.method.process.subprocess/src/com/actionsoft/apps/coe/method/process/subprocess/observers/node/NodeSubject.java @@ -0,0 +1,182 @@ +package com.actionsoft.apps.coe.method.process.subprocess.observers.node; + +import com.actionsoft.apps.coe.method.process.subprocess.constant.SubProcessConst; +import com.actionsoft.apps.coe.method.process.subprocess.graph.component.AbstractDefinitionHandle; +import com.actionsoft.apps.coe.method.process.subprocess.mode.ScopeShapeMonitor; +import com.actionsoft.apps.coe.method.process.subprocess.observers.Observer; +import com.actionsoft.apps.coe.method.process.subprocess.observers.Subject; +import com.alibaba.fastjson.JSONObject; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * @author oYang + * @Description 当前展开或者闭合的操作节点的主题类 + * @createTime 2023年06月16日 10:19:00 + */ +public class NodeSubject implements Subject { + + private AbstractDefinitionHandle definitionHandle; // 总图 define 处理器 + private ScopeShapeMonitor scopeShapeMonitor; // 总图目前已存在的范围框监视模型 + private String scopeShapeId; // 当前展开或者闭合的节点ID + private double scopeX; // 当前展开或者闭合的节点 x + private double scopeY; // 当前展开或者闭合的节点 y + private double scopeW; // 当前展开或者闭合的节点 w + private double scopeH; // 当前展开或者闭合的节点 h + private String action; // expand / close + private List rightObservers = new ArrayList<>(); + private List bottomObservers = new ArrayList<>(); + + public NodeSubject(AbstractDefinitionHandle definitionHandle, ScopeShapeMonitor scopeShapeMonitor, String scopeShapeId, String action) { + this.definitionHandle = definitionHandle; + this.scopeShapeMonitor = scopeShapeMonitor; + this.scopeShapeId = scopeShapeId; + + JSONObject props = this.definitionHandle.getShapeByProps(scopeShapeId); + this.scopeX = props.getDoubleValue("x"); + this.scopeY = props.getDoubleValue("y"); + this.scopeW = props.getDoubleValue("w"); + this.scopeH = props.getDoubleValue("h"); + + this.action = action; + } + + // 构建当前节点的观察者列表 + public void buildObservers(){ + JSONObject elements = definitionHandle.getElements(); + for (String key : elements.keySet()) { + JSONObject ele = elements.getJSONObject(key); + if ("linker".equals(ele.getString("name"))) continue; // 连线不在这处理 + if (key.equals(scopeShapeId)) continue; // 当前被操作的节点 不处理 + if (scopeShapeMonitor.checkShapeIsScopeInRange(key)) continue; // 在已存在的范围框内部的元素不在这处理 + JSONObject props = ele.getJSONObject("props"); + double x = props.getDoubleValue("x"); + double y = props.getDoubleValue("y"); + NodeObserver nodeObserver = new NodeObserver(definitionHandle, scopeShapeMonitor, key); + if (scopeX < x) { + addRightNodeObserver(nodeObserver); + } + if (scopeY < y) { + addBottomNodeObserver(nodeObserver); + } + } + } + + public void setScopeW(double scopeW) { + // 计算 x 方向上的增量 + if ("expand".equals(action)){ // 展开操作 + double colMaxScopeW = getTheSameColMaxScopeW(); + if (scopeW > colMaxScopeW){ + double deltaX = scopeW - colMaxScopeW; + notifyRightObservers(deltaX, 0); + } + }else { // 闭合操作 + double colMaxScopeW = getTheSameColMaxScopeWUnSelf(); + if (this.scopeW > colMaxScopeW) { + double deltaX = colMaxScopeW - this.scopeW; + notifyRightObservers(deltaX, 0); + } + } + } + + public void setScopeH(double scopeH) { + // 计算 y 方向上的增量 + if ("expand".equals(action)){ // 展开操作 + double rowMaxScopeH = getTheSameRowMaxScopeH(); + if (scopeH > rowMaxScopeH){ + double deltaY = scopeH - rowMaxScopeH; + notifyBottomObservers(0, deltaY); + } + }else { // 闭合操作 + double rowMaxScopeH = getTheSameRowMaxScopeHUnSelf(); + if (this.scopeH > rowMaxScopeH) { + double delatY = rowMaxScopeH - this.scopeH; + notifyBottomObservers(0, delatY); + } + } + } + + // 获取当前操作节点同一列节点的最大宽度 + private double getTheSameColMaxScopeW(){ + JSONObject elements = definitionHandle.getElements(); + JSONObject props = elements.keySet().stream() + .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")) && scopeX == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x")) + .map(key -> elements.getJSONObject(key).getJSONObject("props")) + .max(Comparator.comparing(o -> o.getDoubleValue("w"))) + .orElse(null); + return props.getDoubleValue("w"); + } + + // 获取当前操作节点同一列节点的最大宽度 不包含当前操作节点 + private double getTheSameColMaxScopeWUnSelf(){ + JSONObject elements = definitionHandle.getElements(); + JSONObject props = elements.keySet().stream() + .filter(key -> !key.equals(scopeShapeId) && !"linker".equals(elements.getJSONObject(key).getString("name")) && scopeX == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("x")) + .map(key -> elements.getJSONObject(key).getJSONObject("props")) + .max(Comparator.comparing(o -> o.getDoubleValue("w"))) + .orElse(null); + if (props == null) // 如果为空 说明同一列就一个节点就是当前操作的节点 + return SubProcessConst.SUB_PROCESS_SHAPE_W; + return props.getDoubleValue("w"); + } + + // 获取当前操作节点同一行节点的最大高度 + private double getTheSameRowMaxScopeH(){ + JSONObject elements = definitionHandle.getElements(); + JSONObject props = elements.keySet().stream() + .filter(key -> !"linker".equals(elements.getJSONObject(key).getString("name")) && scopeY == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y")) + .map(key -> elements.getJSONObject(key).getJSONObject("props")) + .max(Comparator.comparing(o -> o.getDoubleValue("h"))) + .orElse(null); + return props.getDoubleValue("h"); + } + + // 获取当前操作节点同一行节点的最大高度 不包含当前操作节点 + private double getTheSameRowMaxScopeHUnSelf(){ + JSONObject elements = definitionHandle.getElements(); + JSONObject props = elements.keySet().stream() + .filter(key -> !key.equals(scopeShapeId) && !"linker".equals(elements.getJSONObject(key).getString("name")) && scopeY == elements.getJSONObject(key).getJSONObject("props").getDoubleValue("y")) + .map(key -> elements.getJSONObject(key).getJSONObject("props")) + .max(Comparator.comparing(o -> o.getDoubleValue("h"))) + .orElse(null); + if (props == null) + return SubProcessConst.SUB_PROCESS_SHAPE_H; + return props.getDoubleValue("h"); + } + + @Override + public void addRightNodeObserver(Observer o) { + rightObservers.add(o); + } + + @Override + public void addBottomNodeObserver(Observer o) { + bottomObservers.add(o); + } + + @Override + public void removeRightObserver(Observer o) { + rightObservers.remove(o); + } + + @Override + public void removeBottomObserver(Observer o) { + bottomObservers.remove(o); + } + + @Override + public void notifyRightObservers(double deltaX, double deltaY) { + for (Observer observer : rightObservers) { + observer.update(deltaX, deltaY); + } + } + + @Override + public void notifyBottomObservers(double deltaX, double deltaY) { + for (Observer observer : bottomObservers) { + observer.update(deltaX, deltaY); + } + } +}