diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DependencyModelingStage.java b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DependencyModelingStage.java index 12e3efe..9bff055 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DependencyModelingStage.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/stages/DependencyModelingStage.java @@ -79,6 +79,9 @@ //ControlFlowGraph controlFlowGraph = new ControlFlowGraph(dataFlowGraph, model); dependencyGraph = new DependencyGraph(dataFlowGraph, model); + resNodeToCell = ((PushPullSelectionStage) prevStage).getResNodeToCell(); + eventChannelToCell = ((PushPullSelectionStage) prevStage).getEventChannelToCell(); + graph = constructGraph(graph, dependencyGraph); } @@ -177,126 +180,178 @@ Map resNodeCells = new HashMap<>(); mxCell root = (mxCell) graph.getDefaultParent(); - mxCell nodeLayerCell = (mxCell) root.getChildAt(NODE_LAYER); - mxCell dependencyLayerCell = (mxCell) root.getChildAt(DEPENDENCY_LAYER); + mxCell dependencyLayer = (mxCell) root.getChildAt(DEPENDENCY_LAYER); + // トップレベルのリソースノードを探して再帰的にコピー for (ResourceNode resourceNode : dependencyGraph.getDataFlowGraph().getRootResourceNodes()) { - int w = 80; - int h = 30; - - ResourcePath resourcePath = resourceNode.getPrimaryResourcePath(); - mxCell resNodeCell = (mxCell) graph.insertVertex(dependencyLayerCell, null, resourcePath.getLeafResourceName(), - 20, 20, w, h, "strokeColor=green;fillColor=#BBFFBB;shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top"); // insert a resource as a vertex - resNodeCells.put(resourceNode, resNodeCell); - - createCellsOfChildResourceMap(resNodeCells, resNodeCell, resourceNode, w, h); + mxCell oldCell = resNodeToCell.get(resourceNode); + if (oldCell != null) { + mxCell newCell = cloneResourceCellHierarchy(oldCell, dependencyLayer, resNodeCells); + resNodeCells.put(resourceNode, newCell); + } } + return resNodeCells; } - private void createCellsOfChildResourceMap( Map resNodeCells , mxCell parentCell, ResourceNode parentResNode, double w, double h){ - for (ResourceNode resNode: parentResNode.getChildren()) { - ResourcePath resPath = resNode.getPrimaryResourcePath(); - mxCell resNodeCell = (mxCell) graph.insertVertex(parentCell, null, resPath.getName(), 0, 0, w, h,"strokeColor=green;fillColor=#BBFFBB;shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top"); // insert a resource as a vertex - resNodeCells.put(resNode, resNodeCell); - createCellsOfChildResourceMap(resNodeCells, resNodeCell, resNode, w, h); + /** + * 元のセル階層をたどりながら、新しいレイヤー上に同構造のセルツリーを再構築する。 + */ + private mxCell cloneResourceCellHierarchy(mxCell oldCell, mxCell newParent, Map resNodeCells) { + mxGeometry geo = (mxGeometry) oldCell.getGeometry().clone(); + double x = geo.getX(); + double y = geo.getY(); + double w = geo.getWidth(); + double h = geo.getHeight(); + + String label = (String) oldCell.getValue(); + String newStyle = "strokeColor=green;fillColor=#BBFFBB;shape=ellipse;perimeter=ellipsePerimeter;verticalAlign=top"; + + // 新セルを作成して親に追加 + mxCell newCell = (mxCell) graph.insertVertex( + newParent, + null, + label, + x, y, w, h, + newStyle + ); + + // ResourceNode対応づけ(valueまたは他のMap経由で取得) + ResourceNode node = findResourceNodeByCell(oldCell); + if (node != null) { + resNodeCells.put(node, newCell); } + + // 子セルも再帰的にコピー + int childCount = oldCell.getChildCount(); + for (int i = 0; i < childCount; i++) { + mxCell oldChild = (mxCell) oldCell.getChildAt(i); + cloneResourceCellHierarchy(oldChild, newCell, resNodeCells); + } + + return newCell; } - private Map createEventChannelCells(){ + /** + * セルから対応する ResourceNode を逆引きする補助メソッド。 + * (resNodeToCell の逆引きで探す) + */ + private ResourceNode findResourceNodeByCell(mxCell cell) { + for (Map.Entry entry : resNodeToCell.entrySet()) { + if (entry.getValue() == cell) { + return entry.getKey(); + } + } + return null; + } + + private Map createEventChannelCells() { + Map eventChannelCells = new HashMap<>(); mxCell root = (mxCell) graph.getDefaultParent(); - mxCell dependencyLayerCell = (mxCell) root.getChildAt(DEPENDENCY_LAYER); - - Map eventChannelCells = new HashMap<>(); - Map channelOutToCell = new HashMap<>(); + mxCell dependencyLayer = (mxCell) root.getChildAt(DEPENDENCY_LAYER); graph.getModel().beginUpdate(); try { - mxGeometry geoPortIn = new mxGeometry(0, 0.5, PORT_DIAMETER, PORT_DIAMETER); - geoPortIn.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); - geoPortIn.setRelative(true); - - mxGeometry geoPortOut = new mxGeometry(1.0, 0.5, PORT_DIAMETER, PORT_DIAMETER); - geoPortOut.setOffset(new mxPoint(-PORT_RADIUS, -PORT_RADIUS)); - geoPortOut.setRelative(true); - + // EventChannel階層を resNodeToCell と同様に再帰的にコピー for (ChannelNode channelNode : dependencyGraph.getDataFlowGraph().getRootChannelNodes()) { DataTransferChannel channel = channelNode.getChannel(); if (channel.getInputResources().isEmpty()) { - - if (eventChannelCells.get(channel) == null) { - String channelName = channel.getChannelName(); - if (channel.getSelectors().size() > 0) { - channelName += "("; - String delimiter = ""; - for (Selector s : channel.getSelectors()) { - Expression exp = s.getExpression(); - String selectorName = exp.toString(); - channelName += delimiter + selectorName; - delimiter = ", "; - } - channelName += ")"; - } - int w = 40; - int h = 30; - if (channelNode.getChildren().size() > 0) { - w *= 2; - h *= 2; - } - mxCell channelCell = (mxCell) graph.insertVertex(dependencyLayerCell, null, channelName, 150, 20, w, h, "strokeColor=green;fillColor=#BBFFBB;verticalAlign=top"); // insert a channel as a vertex - eventChannelCells.put(channel, channelCell); - - mxCell portOut = new mxCell(null, geoPortOut, "strokeColor=green;fillColor=#BBFFBB;shape=ellipse;perimter=ellipsePerimeter"); - portOut.setVertex(true); - graph.addCell(portOut, channelCell); // insert the output port of a channel - eventChannelCells.put(channel, portOut); - createChildEventChannelVertices(eventChannelCells, channelCell, channelNode, channelOutToCell, geoPortOut, w, h); - } + mxCell oldCell = eventChannelToCell.get(channel); + if (oldCell != null) { + mxCell newCell = cloneEventChannelHierarchy(oldCell, dependencyLayer, eventChannelCells); + eventChannelCells.put(channel, newCell); + } } } - } - finally { + } finally { graph.getModel().endUpdate(); } return eventChannelCells; } - private void createChildEventChannelVertices(Map eventChannelCells, mxCell parentCell, ChannelNode parentChannelNode, - Map channelOutToCell, mxGeometry geoPortOut, int w, int h) { - for (ChannelNode channelNode: parentChannelNode.getChildren()) { - DataTransferChannel channel = channelNode.getChannel(); + private mxCell cloneEventChannelHierarchy(mxCell oldCell, mxCell newParent, Map eventChannelCells) { + mxGeometry geo = (mxGeometry) oldCell.getGeometry(); + if (geo != null) geo = (mxGeometry) geo.clone(); + String label = (String) oldCell.getValue(); + String style = oldCell.getStyle(); - if (channel.getInputResources().isEmpty()) { + mxCell newCell; - if (channelOutToCell.get(channel) == null) { - String channelName = channel.getChannelName(); - if (channel.getSelectors().size() > 0) { - channelName += "("; - String delimiter = ""; - for (Selector s : channel.getSelectors()) { - Expression exp = s.getExpression(); - String selectorName = exp.toString(); - channelName += delimiter + selectorName; - delimiter = ", "; - } - channelName += ")"; - } - mxCell channelCell = (mxCell) graph.insertVertex(parentCell, null, channelName, w / 4, h / 4, w / 2, h / 2, "strokeColor=green;fillColor=#BBFFBB;verticalAlign=top"); // insert a channel as a vertex - eventChannelCells.put(channel, channelCell); + if (oldCell.isVertex()) { + double x = (geo != null) ? geo.getX() : 0; + double y = (geo != null) ? geo.getY() : 0; + double w = (geo != null) ? geo.getWidth() : 40; + double h = (geo != null) ? geo.getHeight() : 30; - mxCell portOut = new mxCell(null, geoPortOut, "strokeColor=green;fillColor=#BBFFBB;shape=ellipse;perimter=ellipsePerimeter"); - portOut.setVertex(true); - graph.addCell(portOut, channelCell); // insert the output port of a channel - channelOutToCell.put(channel, portOut); - createChildEventChannelVertices(eventChannelCells, channelCell, channelNode, channelOutToCell, geoPortOut, w / 2, h / 2); - } + // 親が dependencyLayer なら channelCell、そうでなければ portなど + if (isPortCell(oldCell)) { + // --- ✅ ポート(portOutなど)の場合 --- + mxGeometry geoPort = (geo != null) ? geo : new mxGeometry(1.0, 0.5, 10, 10); + geoPort.setRelative(true); // relativeを明示的に指定 + if (geoPort.getOffset() == null) { + geoPort.setOffset(new mxPoint(-5, -5)); } + + String portStyle = "strokeColor=green;fillColor=#BBFFBB;shape=ellipse;perimeter=ellipsePerimeter"; + newCell = new mxCell(null, geoPort, portStyle); + newCell.setVertex(true); + graph.addCell(newCell, newParent); + + } else { + // --- 通常のchannelノード --- + String newStyle = "strokeColor=green;fillColor=#BBFFBB;verticalAlign=top"; + newCell = (mxCell) graph.insertVertex( + newParent, + null, + label, + x, y, w, h, + newStyle + ); + } + } else { + newCell = new mxCell(label, geo, style); } + + // --- channelとの対応を登録 --- + DataTransferChannel channel = findEventChannelByCell(oldCell); + if (channel != null) { + eventChannelCells.put(channel, newCell); + } + + // --- 子セルを再帰的に処理 --- + int childCount = oldCell.getChildCount(); + for (int i = 0; i < childCount; i++) { + mxCell oldChild = (mxCell) oldCell.getChildAt(i); + cloneEventChannelHierarchy(oldChild, newCell, eventChannelCells); + } + + return newCell; } + /** + * ポートかどうかを判定 + */ + private boolean isPortCell(mxCell cell) { + String style = cell.getStyle(); + if (style == null) return false; + return style.contains("ellipse") || style.contains("perimeter=ellipsePerimeter"); + } + + + private DataTransferChannel findEventChannelByCell(mxCell cell) { + for (Map.Entry entry : eventChannelToCell.entrySet()) { + if (entry.getValue() == cell) { + return entry.getKey(); + } + } + return null; + } + + + private mxGraph insertControlFlowEdges(final Map resNodeCells, final Map eventChNodeCells) { mxCell root = (mxCell) graph.getDefaultParent(); mxCell dependencyLayerCell = (mxCell) root.getChildAt(DEPENDENCY_LAYER);