package ProjectData.SapforData.Functions.UI.Graph; import Common.Current; import Common.UI.UI; import Common.Utils.Utils; import ProjectData.SapforData.Functions.FuncCoordinates; import ProjectData.SapforData.Functions.FuncInfo; import ProjectData.SapforData.Functions.FunctionType; import Visual_DVM_2021.Passes.All.SPF_GetGraphFunctionPositions; import Visual_DVM_2021.Passes.PassCode_2021; import Visual_DVM_2021.Passes.Pass_2021; import com.mxgraph.model.mxCell; import com.mxgraph.model.mxGeometry; import com.mxgraph.swing.mxGraphComponent; import com.mxgraph.util.mxConstants; import com.mxgraph.util.mxEvent; import com.mxgraph.util.mxEventObject; import com.mxgraph.util.mxRectangle; import com.mxgraph.view.mxGraph; import com.mxgraph.view.mxStylesheet; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Hashtable; import java.util.LinkedHashMap; import static com.mxgraph.util.mxConstants.SHAPE_DOUBLE_ELLIPSE; import static com.mxgraph.util.mxConstants.SHAPE_ELLIPSE; public class FunctionsGraphUI extends mxGraph { //-- public final static Timer ffTimer = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Time to Redraw Functions Graph"); Pass_2021.passes.get(PassCode_2021.SPF_GetGraphFunctionPositions).Do(); System.out.println("DONE"); } }); //--- private static final int default_width = 80; private static final int default_height = 30; //форма узлов? // https://progi.pro/kak-sdelat-parallelogrammnuyu-vershinu-v-jgraphx-13032580 //мануал //https://jgraph.github.io/mxgraph/docs/manual_javavis.html //https://jgraph.github.io/mxgraph/java/docs/com/mxgraph/swing/mxGraphComponent.html //общий манул //https://jgraph.github.io/mxgraph/docs/manual_javavis.html#1.3 //манул п кликам? //https://github.com/jgraph/mxgraph/blob/master/java/examples/com/mxgraph/examples/swing/ClickHandler.java //все образцы //https://github.com/jgraph/mxgraph/tree/master/java/examples/com/mxgraph/examples/swing //https://github.com/jgraph/jgraphx/blob/master/src/com/mxgraph/util/mxConstants.java //про размеры //https://stackoverflow.com/questions/51619879/mxgraph-how-to-automatically-resize-mxcell-to-content-width-if-it-exceeds-the //--------------------- //координаты вершин графа // public LinkedHashMap> vertexCoordinates = new LinkedHashMap<>(); protected GraphInfo graph = null; //инфа о вершинах и ребрах. public FunctionsGraphUI(GraphInfo graph_in) { graph = graph_in; //настройки графа setGridEnabled(true); //setAllowNegativeCoordinates(false); setAllowDanglingEdges(false); //запрет на висячие ребра. setCellsEditable(false); //запрет на редактирование клеток setCellsResizable(false); //запрет изменения размера клеток setKeepEdgesInBackground(true); // ребра на задний план. очень важно. setDropEnabled(false); setAutoSizeCells(true); setConnectableEdges(false); setCellsCloneable(false); //-------------------- mxStylesheet stylesheet = getStylesheet(); Hashtable style = new Hashtable(); style.put(mxConstants.STYLE_SHAPE, SHAPE_ELLIPSE); style.put(mxConstants.STYLE_FONTCOLOR, "black"); style.put(mxConstants.STYLE_FILLCOLOR, "yellow"); style.put(mxConstants.STYLE_FONTSIZE, "16"); style.put(mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_BOLD); stylesheet.putCellStyle(FunctionType.Default.toString(), style); //------------------------------------------ style = new Hashtable(); style.put(mxConstants.STYLE_SHAPE, SHAPE_ELLIPSE); style.put(mxConstants.STYLE_FONTCOLOR, "black"); style.put(mxConstants.STYLE_FILLCOLOR, "lightgreen"); style.put(mxConstants.STYLE_FONTSIZE, "16"); style.put(mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_BOLD); stylesheet.putCellStyle(FunctionType.Main.toString(), style); //------------------------------------------ style = new Hashtable(); style.put(mxConstants.STYLE_SHAPE, SHAPE_ELLIPSE); style.put(mxConstants.STYLE_FONTCOLOR, "black"); style.put(mxConstants.STYLE_FILLCOLOR, "lightgray"); style.put(mxConstants.STYLE_FONTSIZE, "16"); style.put(mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_BOLD); // style.put(mxConstants.STYLE_STROKECOLOR, "lawngreen"); это и есть границы. // style.put(mxConstants.STYLE_STROKEWIDTH, 5); stylesheet.putCellStyle(FunctionType.Standard.toString(), style); //------------------------------------------ style = new Hashtable(); style.put(mxConstants.STYLE_SHAPE, SHAPE_ELLIPSE); style.put(mxConstants.STYLE_FONTCOLOR, "white"); style.put(mxConstants.STYLE_FILLCOLOR, "darkred"); style.put(mxConstants.STYLE_FONTSIZE, "16"); style.put(mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_BOLD); stylesheet.putCellStyle(FunctionType.NotFound.toString(), style); //------------------------------------------ style = new Hashtable(); style.put(mxConstants.STYLE_SHAPE, SHAPE_DOUBLE_ELLIPSE); style.put(mxConstants.STYLE_FONTCOLOR, "black"); style.put(mxConstants.STYLE_FILLCOLOR, "lightblue"); style.put(mxConstants.STYLE_FONTSIZE, "16"); style.put(mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_BOLD); // style.put(mxConstants.STYLE_STROKECOLOR, "lawngreen"); это и есть границы. // style.put(mxConstants.STYLE_STROKEWIDTH, 5); stylesheet.putCellStyle("current", style); } //--- // еще один туториал? // https://www.47.gbmse.ru/resources/utility/mxgraph/docs/tutorial.html // //https://github.com/jgraph/mxgraph/tree/master/java/examples/com/mxgraph/examples/swing //https://jgraph.github.io/mxgraph/java/docs/com/mxgraph/swing/mxGraphComponent.html //https://www.47.gbmse.ru/resources/utility/mxgraph/docs/tutorial.html#3.2 public mxGraphComponent Draw() { FuncInfo funcInfo = null; //установить координаты вершин. SetCoordinates(); //пустышка. Object parent = getDefaultParent(); getModel().beginUpdate(); //непосредственное добавление графики //------------------------------------ //размеры //https://stackoverflow.com/questions/51619879/mxgraph-how-to-automatically-resize-mxcell-to-content-width-if-it-exceeds-the // UI.Info("++"); LinkedHashMap mxVertexes = new LinkedHashMap<>(); for (String name : graph.vertexCoordinates.keySet()) { funcInfo = Current.getProject().allFunctions.get(name); String vertexType = funcInfo.type.toString(); if (SPF_GetGraphFunctionPositions.showByCurrentFunction) { FuncInfo current_fi = (FuncInfo) Current.get(Current.Function); if ((current_fi != null) && (funcInfo.funcName.equals(current_fi.funcName))) { vertexType = "current"; } } mxVertexes.put(name, insertVertex(parent, name, //идентификатор вершины. должен быть уникальным. name, //объект не стоит делать. какие то мутки при перетаскивании объектов. //строки-ключа уже достаточно //координаты вершины graph.vertexCoordinates.get(name).getKey(), graph.vertexCoordinates.get(name).getValue(), default_width, default_height, vertexType )); } for (String name : graph.vertexMap.keySet()) { mxCell cell = (mxCell) mxVertexes.get(name); mxRectangle preferred = getPreferredSizeForCell(cell); mxGeometry current = cell.getGeometry(); current.setWidth((preferred.getWidth() > default_width) ? preferred.getWidth() : default_width); //updateCellSize(cell, true); это если просто везде выставить авторазмер. //тут же нам нужно применить его только в случае если ширина меньше чем надо. for (String neigbor : graph.vertexMap.get(name)) { insertEdge(parent, null, //надпись над ребром. "", //вершина 1 mxVertexes.get(name), //вершина 2 mxVertexes.get(neigbor)); } } //------------------------------------ //https://java.hotexamples.com/examples/com.mxgraph.view/mxGraph/setAutoSizeCells/java-mxgraph-setautosizecells-method-examples.html groupCells(); getModel().endUpdate(); //------------------------------------ //обертка графа контролом mxGraphComponent graphComponent = new mxGraphComponent(this); graphComponent.setZoomFactor(1.10); //-- // https://programtalk.com/java-more-examples/com.mxgraph.util.mxEvent.UP/ addListener(mxEvent.CELLS_MOVED, new mxIEventListener() { @Override public void invoke(Object o, mxEventObject mxEventObject) { //Сохранение координат графа при сдвиге узла if (mxEventObject.getProperties().containsKey("cells")) { Object[] cells = (Object[]) mxEventObject.getProperties().get("cells"); for (Object cell_ : cells) { if (cell_ instanceof mxCell) { mxCell cell = (mxCell) cell_; if (cell.isVertex()) { String funcName = (String) cell.getValue(); FuncCoordinates coords = null; // UI.Info(cell.getGeometry().getPoint().toString()); Point point = cell.getGeometry().getPoint(); try { if (Current.getProject().db.funcCoordinates.containsKey(funcName)) { coords = Current.getProject().db.funcCoordinates.get(funcName); coords.name = funcName; coords.X = point.getX(); coords.Y = point.getY(); Current.getProject().db.Update(coords); } else { coords = new FuncCoordinates(); coords.name = funcName; coords.X = point.getX(); coords.Y = point.getY(); Current.getProject().db.Insert(coords); } } catch (Exception ignored) { } } } } } } /* System.out.println("------"); for (String key: mxEventObject.getProperties().keySet()){ System.out.println(key+" : "+ mxEventObject.getProperties().get(key)); } System.out.println("------"); */ }); graphComponent.getGraphControl().setComponentPopupMenu(new FunctionsGraphMenu()); //обработка клика мышом. graphComponent.getGraphControl().addMouseListener(new MouseAdapter() { public void mouseReleased(MouseEvent e) { System.out.println("Released"); Object cell = graphComponent.getCellAt(e.getX(), e.getY()); if (cell != null) { mxCell mx_cell = (mxCell) cell; if (mx_cell.isVertex()) { String func_name = (String) mx_cell.getValue(); FuncInfo fi = Current.getProject().allFunctions.get(func_name); switch (e.getClickCount()) { case 1: Current.set(Current.SelectedFunction, fi); break; case 2: switch (fi.type) { case Default: case Main: fi.Show(true); break; case Standard: case NotFound: UI.Info("процедура " + Utils.Brackets(func_name) + " " + fi.type.getDescription()); break; } break; } } } } }); graphComponent.getViewport().setBackground(Color.WHITE); return graphComponent; } //по умолчанию ничего не меняем. public void SetCoordinates() { } public void SaveCoords() { } }