From 90f8b8f19a0549531029d758ce2cdf4cf00a1e93 Mon Sep 17 00:00:00 2001 From: stephane <stephane.dervaux@inrae.fr> Date: Mon, 9 Sep 2024 17:16:28 +0200 Subject: [PATCH] =?UTF-8?q?add=20save=20node=20position=20in=20PO=C2=B2=20?= =?UTF-8?q?file=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../po2vocabmanager/utils/JavaConnector.java | 9 + .../dataView/ItineraryOverviewController.java | 196 ++++++++++-------- .../po2vocabmanager/graph/graph-creator.js | 5 + 3 files changed, 129 insertions(+), 81 deletions(-) diff --git a/src/main/java/fr/inra/po2vocabmanager/utils/JavaConnector.java b/src/main/java/fr/inra/po2vocabmanager/utils/JavaConnector.java index c42f32ba..9ef592dd 100644 --- a/src/main/java/fr/inra/po2vocabmanager/utils/JavaConnector.java +++ b/src/main/java/fr/inra/po2vocabmanager/utils/JavaConnector.java @@ -23,6 +23,7 @@ import fr.inra.po2vocabmanager.model.DataNode; import fr.inrae.po2engine.model.dataModel.CompositionFile; import fr.inrae.po2engine.model.dataModel.ItineraryFile; import fr.inrae.po2engine.model.dataModel.StepFile; +import org.json.JSONArray; import org.json.JSONObject; import java.util.HashMap; @@ -47,6 +48,14 @@ public class JavaConnector { System.out.println("log : " + message); } + public void nodeDragged(String allNodes) throws NumberFormatException{ + JSONArray nodesArray = new JSONArray(allNodes); + nodesArray.forEach(node -> { + JSONObject obj = (JSONObject) node; + this.itiFile.setNodePosition(obj.optString("id", ""), obj.optDouble("x", 0.0) / 72.0, obj.optDouble("y", 0.0) / 72.0); + }); + } + public void addEdge(String source, String target) { if(!MainApp.getDataControler().canEdit()) { return; diff --git a/src/main/java/fr/inra/po2vocabmanager/view/dataView/ItineraryOverviewController.java b/src/main/java/fr/inra/po2vocabmanager/view/dataView/ItineraryOverviewController.java index a1e9ed97..952e72e0 100644 --- a/src/main/java/fr/inra/po2vocabmanager/view/dataView/ItineraryOverviewController.java +++ b/src/main/java/fr/inra/po2vocabmanager/view/dataView/ItineraryOverviewController.java @@ -67,6 +67,7 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; public class ItineraryOverviewController { @@ -88,6 +89,7 @@ public class ItineraryOverviewController { private JavaConnector jc; private ListView<TextField> listProduct; private WebView browser; + private ItineraryFile itiFile; @FXML private void initialize() { @@ -104,96 +106,41 @@ public class ItineraryOverviewController { } public void showNodeDetails(DataNode node) { - Tools.addProgress(ProgressPO2.GRAPH, "creating graph"); - ItineraryFile file = (ItineraryFile) node.getFile(); - file.checkValue(); - WebView browser = new WebView(); - ap.getChildren().clear(); - ap.getChildren().add(browser); - AnchorPane.setTopAnchor(browser, 0.0); - AnchorPane.setLeftAnchor(browser, 0.0); - AnchorPane.setRightAnchor(browser, 0.0); - AnchorPane.setBottomAnchor(browser, 0.0); - WebEngine webEngine = browser.getEngine(); - webEngine.setJavaScriptEnabled(true); + this.itiFile = (ItineraryFile) node.getFile(); - listIdStep = new HashMap<>(); - listIdComposition = new HashMap<>(); listProduct = new ListView<>(); + this.itiFile.checkValue(); - // Important. garder une référence au javaconnector pour eviter le garbage collector ! bug openJDK - jc = new JavaConnector(file, listIdStep, listIdComposition); - webEngine.setOnAlert(event -> { - Alert alert = new Alert(Alert.AlertType.INFORMATION); - alert.initOwner(MainApp.primaryStage); - alert.initModality(Modality.WINDOW_MODAL); - alert.setContentText(event.getData()); - alert.showAndWait(); - }); - webEngine.setOnError(event -> { - Alert alert = new Alert(Alert.AlertType.ERROR); - alert.initOwner(MainApp.primaryStage); - alert.initModality(Modality.WINDOW_MODAL); - alert.setContentText(event.getMessage()); - alert.showAndWait(); - }); - webEngine.setConfirmHandler(event -> { - Alert alert = new Alert(Alert.AlertType.INFORMATION); - alert.initOwner(MainApp.primaryStage); - alert.initModality(Modality.WINDOW_MODAL); - alert.setContentText(event); - alert.showAndWait(); - return true; - }); - webEngine.getLoadWorker().stateProperty().addListener( - new ChangeListener() { - @Override - public void changed(ObservableValue observable, Object oldValue, Object newValue) { - if (newValue == Worker.State.SUCCEEDED) { - JSObject jsobj = (JSObject) webEngine.executeScript("window"); - jsobj.setMember("javaConnector", jc); -// webEngine.executeScript("var firebug=document.createElement('script');firebug.setAttribute('src','https://lupatec.eu/getfirebug/firebug-lite-compressed.js');document.body.appendChild(firebug);(function(){if(window.firebug.version){firebug.init();}else{setTimeout(arguments.callee);}})();void(firebug);"); - Platform.runLater(() -> { - new Thread(() -> { - generateGraph2(browser, file, file.getItineraryName() + " (" + file.getItineraryNumber()+")", listIdStep, listIdComposition); - Tools.delProgress(ProgressPO2.GRAPH); - }).start(); - }); - } - } - } - ); prodOfbox.getChildren().clear(); - Label lnum = new Label(file.getItineraryNumber()); + Label lnum = new Label(itiFile.getItineraryNumber()); Label lname = new Label(" -- name : "); - TextField itiName = new TextField(file.getItineraryName()); + TextField itiName = new TextField(itiFile.getItineraryName()); itiName.disableProperty().bind(this.mainApp.getEditProperty().not()); itiName.setStyle(" -fx-text-fill: black; -fx-opacity: 1;"); itiName.textProperty().addListener((observableValue, oldValue, newValue) -> { - file.getProcessFile().getData().setModified(true); - + itiFile.getProcessFile().getData().setModified(true); if(newValue != null && !newValue.isEmpty()) { - file.itineraryNameProperty().set(newValue); + itiFile.itineraryNameProperty().set(newValue); } else { - file.itineraryNameProperty().set(""); + itiFile.itineraryNameProperty().set(""); } } ); Label separator = new Label(""); Label connectedComponent = new Label( ""); - connectedComponent.visibleProperty().bind(file.connectedComposant.greaterThan(1)); - connectedComponent.textProperty().bind(new SimpleStringProperty(" -- ").concat(file.connectedComposant.asString().concat(" connected components"))); + connectedComponent.visibleProperty().bind(itiFile.connectedComposant.greaterThan(1)); + connectedComponent.textProperty().bind(new SimpleStringProperty(" -- ").concat(itiFile.connectedComposant.asString().concat(" connected components"))); separator.setMaxWidth(Double.MAX_VALUE); HBox bb = new HBox(); Background warn = new Background(new BackgroundFill(javafx.scene.paint.Color.DARKORANGE,null,null)); Background norm = new Background(new BackgroundFill(null,null,null)); - bb.backgroundProperty().bind(Bindings.when(file.connectedComposant.greaterThan(1)).then(warn).otherwise(norm)); + bb.backgroundProperty().bind(Bindings.when(itiFile.connectedComposant.greaterThan(1)).then(warn).otherwise(norm)); bb.setAlignment(Pos.CENTER_RIGHT); bb.setHgrow(separator, Priority.ALWAYS); @@ -213,15 +160,14 @@ public class ItineraryOverviewController { VBox box = new VBox(); box.getChildren().add(listProduct); - for (String c : file.getProductsOfInterest()) { + for (String c : itiFile.getProductsOfInterest()) { if (!c.isEmpty()) { TextField comb = new TextField(); comb.setText(c); comb.editableProperty().bind(MainApp.getDataControler().getCanEditProperty()); UITools.addAutoComplete(comb, Ontology.listComponentProperty()); -// UITools.addPopOver(comb, Ontology.Component); listProduct.getItems().add(comb); - comb.textProperty().addListener((observableValue, s, t1) -> updateListProduct(file)); + comb.textProperty().addListener((observableValue, s, t1) -> updateListProduct(itiFile)); } } listProduct.setCellFactory(cellData -> { @@ -236,7 +182,7 @@ public class ItineraryOverviewController { setGraphic(null); } else { Button delButton = new Button(null, new ImageView(UITools.getImage("resources/images/del_16.png"))); - delButton.setOnMouseClicked(event1 -> {listProduct.getItems().remove(item);updateListProduct(file);}); + delButton.setOnMouseClicked(event1 -> {listProduct.getItems().remove(item);updateListProduct(itiFile);}); delButton.disableProperty().bind(MainApp.getDataControler().getCanEditProperty().not()); HBox hBox = new HBox(); @@ -254,8 +200,8 @@ public class ItineraryOverviewController { UITools.addAutoComplete(comb, Ontology.listComponentProperty()); // UITools.addPopOver(comb, Ontology.Component); listProduct.getItems().add(comb); - updateListProduct(file); - comb.textProperty().addListener((observableValue, s, t1) -> updateListProduct(file)); + updateListProduct(itiFile); + comb.textProperty().addListener((observableValue, s, t1) -> updateListProduct(itiFile)); }); @@ -269,15 +215,17 @@ public class ItineraryOverviewController { exportImg.setGraphic(new ImageView(UITools.getImage("resources/images/file-export-16.png"))); - Button reinitScreen = new Button("reinit view"); - reinitScreen.setGraphic(new ImageView(UITools.getImage("resources/images/resize-expand_16.png"))); + Button resetLayout = new Button("reset nodes position"); + resetLayout.setGraphic(new ImageView(UITools.getImage("resources/images/resize-expand_16.png"))); - HBox bbb = new HBox(exportImg, reinitScreen); + HBox bbb = new HBox(exportImg, resetLayout); prodOfbox.getChildren().addAll(prodLabel, listProduct, graphTips, bbb); - reinitScreen.setOnAction(actionEvent -> { - browser.getEngine().executeScript("graph.reinit()"); + + resetLayout.setOnAction(actionEvent -> { + this.itiFile.clearNodePosition(); + drawGraph(); }); exportImg.setOnAction(actionEvent -> { @@ -306,6 +254,69 @@ public class ItineraryOverviewController { // generateGraphSmart(sp2, file.getItinerary(), file.getItineraryName() + " (" + file.getItineraryNumber()+")"); // generateGraph(sp2, file.getItinerary(), file.getItineraryName() + " (" + file.getItineraryNumber()+")"); + drawGraph(); + + } + + private void drawGraph() { + Tools.addProgress(ProgressPO2.GRAPH, "creating graph"); + browser = new WebView(); + AnchorPane.setTopAnchor(browser, 0.0); + AnchorPane.setLeftAnchor(browser, 0.0); + AnchorPane.setRightAnchor(browser, 0.0); + AnchorPane.setBottomAnchor(browser, 0.0); + ap.getChildren().clear(); + ap.getChildren().add(browser); + + WebEngine webEngine = browser.getEngine(); + webEngine.setJavaScriptEnabled(true); + + listIdStep = new HashMap<>(); + listIdComposition = new HashMap<>(); + + // Important. garder une référence au javaconnector pour eviter le garbage collector ! bug openJDK + jc = new JavaConnector(this.itiFile, listIdStep, listIdComposition); + webEngine.setOnAlert(event -> { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.initOwner(MainApp.primaryStage); + alert.initModality(Modality.WINDOW_MODAL); + alert.setContentText(event.getData()); + alert.showAndWait(); + }); + webEngine.setOnError(event -> { + Alert alert = new Alert(Alert.AlertType.ERROR); + alert.initOwner(MainApp.primaryStage); + alert.initModality(Modality.WINDOW_MODAL); + alert.setContentText(event.getMessage()); + alert.showAndWait(); + }); + webEngine.setConfirmHandler(event -> { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.initOwner(MainApp.primaryStage); + alert.initModality(Modality.WINDOW_MODAL); + alert.setContentText(event); + alert.showAndWait(); + return true; + }); + webEngine.getLoadWorker().stateProperty().addListener( + new ChangeListener() { + @Override + public void changed(ObservableValue observable, Object oldValue, Object newValue) { + if (newValue == Worker.State.SUCCEEDED) { + JSObject jsobj = (JSObject) webEngine.executeScript("window"); + jsobj.setMember("javaConnector", jc); +// webEngine.executeScript("var firebug=document.createElement('script');firebug.setAttribute('src','https://lupatec.eu/getfirebug/firebug-lite-compressed.js');document.body.appendChild(firebug);(function(){if(window.firebug.version){firebug.init();}else{setTimeout(arguments.callee);}})();void(firebug);"); + + Platform.runLater(() -> { + new Thread(() -> { + generateGraph2(browser, itiFile, itiFile.getItineraryName() + " (" + itiFile.getItineraryNumber()+")", listIdStep, listIdComposition); + Tools.delProgress(ProgressPO2.GRAPH); + }).start(); + }); + } + } + } + ); Platform.runLater(() -> { webEngine.load(MainApp.class.getResource("graph/graph.html").toExternalForm()); @@ -327,6 +338,7 @@ public class ItineraryOverviewController { HashMap<StepFile, MutableNode> listStepNode = new HashMap<>(); HashMap<CompositionFile, MutableNode> listCompo = new HashMap<>(); + AtomicBoolean positionExist = new AtomicBoolean(false); itiFile.getListStep().filtered(s -> s.getFather() != null).forEach(s -> { StepFile father = s.getFather(); @@ -337,6 +349,11 @@ public class ItineraryOverviewController { ms.add("observation", father.getObservationFiles().size()); ms.add("hat", "yes"); ms.add("type", "step"); + String pos = itiFile.getNodePosition(father.getUuid()); + if(pos != null) { + ms.add("pos", pos); + positionExist.set(true); + } listIdStep.put(father.getUuid(), father); g.add(ms); @@ -352,6 +369,11 @@ public class ItineraryOverviewController { ms.add("observation", s.getObservationFiles().size()); ms.add("hat", "no"); ms.add("type", "step"); + String pos = itiFile.getNodePosition(s.getUuid()); + if(pos != null) { + ms.add("pos", pos); + positionExist.set(true); + } listIdStep.put(s.getUuid(),s); listStepNode.put( s, ms); g.add(ms); @@ -403,6 +425,11 @@ public class ItineraryOverviewController { pc.add(Color.named("red")); pc.add("id", en.getKey().getUuid()); pc.add("type", "composition"); + String pos = itiFile.getNodePosition(en.getKey().getUuid()); + if(pos != null) { + pc.add("pos", pos); + positionExist.set(true); + } listIdComposition.put(en.getKey().getUuid(), en.getKey()); g.add(pc); listCompo.put(en.getKey(), pc); @@ -420,9 +447,14 @@ public class ItineraryOverviewController { Arrays.asList(new GraphvizCmdLineEngine(), new GraphvizV8Engine(), new GraphvizJdkEngine())); Graphviz.useEngine(listEngine); Graphviz viz = Graphviz.fromGraph(g); - String json = viz.render(Format.JSON).toString(); + String json = ""; + if(positionExist.get()) { + json = viz.engine(Engine.NEATO).render(Format.JSON).toString(); + } else { + json = viz.engine(Engine.DOT).yInvert(true).render(Format.JSON).toString(); + } // try { -// viz.render(Format.PNG).toFile(new File("resources/graph.png")); +// viz.engine(Engine.NEATO).render(Format.PNG).toFile(new File("resources/graph.png")); // } catch (IOException e) { // throw new RuntimeException(e); // } @@ -438,6 +470,9 @@ public class ItineraryOverviewController { if(!node.optString("pos").isEmpty()) { String[] pos = node.getString("pos").split(","); maxHeaght = Math.max(maxHeaght,Double.valueOf(pos[1]) ); + if(!positionExist.get()) { // pos calculatedby dot algo + itiFile.setNodePosition(node.getString("id"),+Double.valueOf(pos[0]) / 72.0, Double.valueOf(pos[1]) / 72.0 ); + } } } for (Integer i = 0; i < listGraphNode.length(); i++) { @@ -445,9 +480,8 @@ public class ItineraryOverviewController { if(!node.optString("pos").isEmpty()) { String[] pos = node.getString("pos").split(","); String label = node.getString("label").replaceAll("\\\\N", ""); - Double posX = Double.valueOf(pos[0]) - 100.0; - Double posY = maxHeaght - (Double.valueOf(pos[1]) - 100.0); - + Double posX = Double.valueOf(pos[0]); + Double posY = Double.valueOf(pos[1]); if (node.getString("type").equalsIgnoreCase("step")) { Platform.runLater(() -> { String type = node.getString("hat").equalsIgnoreCase("yes") ? "hat" : "step"; diff --git a/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.js b/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.js index b155d110..d0c5284c 100644 --- a/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.js +++ b/src/main/resources/fr/inra/po2vocabmanager/graph/graph-creator.js @@ -139,6 +139,7 @@ }) .on("end", function(d) { thisGraph.MouseUp.call(thisGraph, d3.select(this), d); + thisGraph.javaFXNodeDragged(thisGraph.nodes); }); // listen for key events @@ -658,6 +659,10 @@ GraphCreator.prototype.javaFXHighLightNode = function(node) { javaConnector.highlightStep(JSON.stringify(node)); } +GraphCreator.prototype.javaFXNodeDragged = function(nodes) { + javaConnector.nodeDragged(JSON.stringify(nodes)); +} + var width = window.innerWidth, height = window.innerHeight; -- GitLab