2023-09-17 22:13:42 +03:00
|
|
|
|
package ProjectData.SapforData.Functions.UI.Graph;
|
2024-10-07 00:58:29 +03:00
|
|
|
|
import Common_old.Current;
|
|
|
|
|
|
import Common_old.UI.UI;
|
|
|
|
|
|
import Common_old.Utils.Utils;
|
2023-09-17 22:13:42 +03:00
|
|
|
|
import ProjectData.SapforData.Functions.FuncCoordinates;
|
|
|
|
|
|
import ProjectData.SapforData.Functions.FuncInfo;
|
|
|
|
|
|
import ProjectData.SapforData.Functions.FunctionType;
|
2023-11-19 02:12:44 +03:00
|
|
|
|
import Visual_DVM_2021.Passes.All.SPF_GetGraphFunctionPositions;
|
|
|
|
|
|
import Visual_DVM_2021.Passes.PassCode_2021;
|
|
|
|
|
|
import Visual_DVM_2021.Passes.Pass_2021;
|
2023-09-17 22:13:42 +03:00
|
|
|
|
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) {
|
|
|
|
|
|
Pass_2021.passes.get(PassCode_2021.SPF_GetGraphFunctionPositions).Do();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
//---
|
|
|
|
|
|
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<String, Pair<Double, Double>> 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<String, Object> style = new Hashtable<String, Object>();
|
|
|
|
|
|
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<String, Object>();
|
|
|
|
|
|
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<String, Object>();
|
|
|
|
|
|
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<String, Object>();
|
|
|
|
|
|
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<String, Object>();
|
|
|
|
|
|
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<String, Object> 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) {
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
graphComponent.getGraphControl().setComponentPopupMenu(new FunctionsGraphMenu());
|
|
|
|
|
|
|
|
|
|
|
|
//обработка клика мышом.
|
|
|
|
|
|
graphComponent.getGraphControl().addMouseListener(new MouseAdapter() {
|
|
|
|
|
|
public void mouseReleased(MouseEvent e) {
|
|
|
|
|
|
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() {
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|