Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi-substation layout feature #105

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@
*/
public class DiagramViewer extends Application {

private static Stage primaryStage;

public void start(Stage primaryStage) throws IOException {
DiagramViewer.primaryStage = primaryStage;

FXMLLoader loader = new FXMLLoader();
loader.setLocation(Objects.requireNonNull(getClass().getResource("/mainView.fxml")));
BorderPane root = loader.load();
Expand All @@ -35,4 +39,8 @@ public void start(Stage primaryStage) throws IOException {
public static void main(String[] args) {
Application.launch(DiagramViewer.class);
}

public static Stage getPrimaryStage() {
return DiagramViewer.primaryStage;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@ private void initialize() {
model.networkProperty().addListener((observableValue, oldNetwork, newNetwork) -> {
sldViewController.updateFrom(model.networkProperty());
initSubstationsTree(newNetwork);
try {
sldViewController.initMatrixSubstationList(newNetwork);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});

showNames.selectedProperty().addListener((observable, oldValue, newValue) -> vlTree.refresh());
Expand Down Expand Up @@ -216,6 +221,11 @@ public TreeItem<Container<?>> fromString(String string) {

nadViewController.addListener((observable, oldValue, newValue) -> updateNadDiagrams());
sldViewController.addListener((observable, oldValue, newValue) -> updateSldDiagrams());
sldViewController.updateSldButton.setOnAction(actionEvent -> {
actionEvent.consume();
updateSldDiagrams();
});

}

private void clearSelection() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.powsybl.diagram.viewer.sld;

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.Spinner;

public class MatrixShapeViewController {

@FXML
public Label substationName;

@FXML
public Label substationId;

@FXML
public Spinner<Integer> row;

@FXML
public Spinner<Integer> column;

public void setSubstationNameValue(String text) {
this.substationName.setText(text);
}

public String getSubstationNameValue() {
return substationName.getText();
}

public void setRowValue(Integer row) {
this.row.getValueFactory().setValue(row);
}

public Integer getRowValue() {
return row.getValue();
}

public void setColumnValue(Integer column) {
this.column.getValueFactory().setValue(column);
}

public Integer getColumnValue() {
return column.getValue();
}

public void setSubstationIdValue(String substationId) {
this.substationId.setText(substationId);
}

public Label getSubstationIdValue() {
return substationId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,37 @@
*/
package com.powsybl.diagram.viewer.sld;

import com.powsybl.diagram.viewer.DiagramViewer;
import com.powsybl.diagram.viewer.common.AbstractDiagramController;
import com.powsybl.diagram.viewer.common.ContainerResult;
import com.powsybl.iidm.network.Container;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.Switch;
import com.powsybl.sld.SingleLineDiagram;
import com.powsybl.sld.SldParameters;
import com.powsybl.sld.layout.HorizontalZoneLayoutFactory;
import com.powsybl.sld.layout.MatrixZoneLayoutFactory;
import com.powsybl.sld.layout.VoltageLevelLayoutFactoryCreator;
import com.powsybl.sld.layout.ZoneLayoutFactory;
import com.powsybl.sld.svg.styles.StyleProvider;
import javafx.beans.binding.Bindings;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;
import javafx.scene.Cursor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
* @author Thomas Adam <tadam at slicom.fr>
Expand All @@ -33,6 +46,7 @@ public class SingleLineDiagramController extends AbstractDiagramController {

private static final Logger LOGGER = LoggerFactory.getLogger(SingleLineDiagramController.class);

private static Service<ContainerResult> sldService;
private StringProperty metadataContent;
private StringProperty graphContent;

Expand Down Expand Up @@ -63,6 +77,17 @@ public void createDiagram(SingleLineDiagramJsHandler jsHandler,
}
});
setUpListenerOnWebViewChanges(jsHandler);
// Manage cursor look above WebView
DiagramViewer.getPrimaryStage().getScene().getRoot().cursorProperty().addListener((observable, oldValue, newValue) -> {
if (Worker.State.SUCCEEDED == diagramWebView.getEngine().getLoadWorker().stateProperty().get()) {
Document doc = diagramWebView.getEngine().getDocument();
Element body = (Element)
doc.getElementsByTagName("body").item(0);
String style = body.getAttribute("style");
body.setAttribute("style", "cursor: " + ((newValue == Cursor.WAIT) ? "wait" : "default") + ";" + style);
}
});

containerResult.metadataContentProperty().addListener((obs, oldV, newV) -> jsHandler.setMetadata(containerResult.metadataContentProperty().get()));

// Metadata & Graph binding
Expand All @@ -78,34 +103,48 @@ public static void updateDiagram(Network network,
Container<?> container,
// PositionVoltageLevelLayoutFactory
VoltageLevelLayoutFactoryCreator voltageLevelLayoutFactoryCreator) {

if (container instanceof Network) {
return;
if (sldService != null && sldService.isRunning()) {
sldService.cancel();
}
Service<ContainerResult> sldService = new Service<>() {
sldService = new Service<>() {
@Override
protected Task<ContainerResult> createTask() {
return new Task<>() {
@Override
protected ContainerResult call() throws IOException {
ContainerResult result = new ContainerResult();
List<String> substationList = new ArrayList<>();
try (StringWriter svgWriter = new StringWriter();
StringWriter metadataWriter = new StringWriter();
StringWriter jsonWriter = new StringWriter()) {

ZoneLayoutFactory zoneLayoutFactory = model.getZoneLayoutFactory();
if (model.getZoneLayoutFactory() instanceof MatrixZoneLayoutFactory) {
substationList = Arrays.stream(model.getMatrix())
.flatMap(Arrays::stream)
.filter(Predicate.not(String::isEmpty))
.toList();
zoneLayoutFactory = substationList.isEmpty() ?
new HorizontalZoneLayoutFactory() : new MatrixZoneLayoutFactory(model.getMatrix());
}
SldParameters sldParameters = new SldParameters()
.setLayoutParameters(model.getLayoutParameters())
.setSvgParameters(model.getSvgParameters())
.setComponentLibrary(model.getComponentLibrary())
.setSubstationLayoutFactory(model.getSubstationLayoutFactory())
.setStyleProviderFactory(model::getStyleProvider)
.setVoltageLevelLayoutFactoryCreator(voltageLevelLayoutFactoryCreator);

SingleLineDiagram.draw(network, container.getId(),
svgWriter,
metadataWriter,
sldParameters);

.setVoltageLevelLayoutFactoryCreator(voltageLevelLayoutFactoryCreator)
.setZoneLayoutFactory(zoneLayoutFactory);
if (container instanceof Network network && !substationList.isEmpty()) {
SingleLineDiagram.drawMultiSubstations(network, substationList,
svgWriter,
metadataWriter,
sldParameters);
} else {
SingleLineDiagram.draw(network, container.getId(),
svgWriter,
metadataWriter,
sldParameters);
}
svgWriter.flush();
metadataWriter.flush();
result.svgContentProperty().set(svgWriter.toString());
Expand All @@ -117,7 +156,15 @@ protected ContainerResult call() throws IOException {
};
}
};

// Show waiting cursor during task execution
DiagramViewer.getPrimaryStage().getScene()
.getRoot()
.cursorProperty()
.bind(Bindings.when(sldService.runningProperty())
.then(Cursor.WAIT)
.otherwise(Cursor.DEFAULT)
);
sldService.setOnCancelled(event -> DiagramViewer.getPrimaryStage().getScene().getRoot().setCursor(Cursor.DEFAULT));
sldService.setOnSucceeded(event -> containerResult.setValue((ContainerResult) event.getSource().getValue()));
sldService.setOnFailed(event -> {
Throwable exception = event.getSource().getException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@

import com.powsybl.diagram.viewer.common.DiagramModel;
import com.powsybl.iidm.network.Network;
import com.powsybl.sld.cgmes.dl.iidm.extensions.*;
import com.powsybl.sld.cgmes.layout.*;
import com.powsybl.sld.cgmes.dl.iidm.extensions.NetworkDiagramData;
import com.powsybl.sld.cgmes.layout.CgmesSubstationLayoutFactory;
import com.powsybl.sld.layout.*;

import com.powsybl.sld.library.ComponentLibrary;
import com.powsybl.sld.svg.SvgParameters;
import com.powsybl.sld.svg.styles.*;
import com.powsybl.sld.svg.styles.iidm.*;
import com.powsybl.sld.svg.styles.iidm.HighlightLineStateStyleProvider;
import com.powsybl.sld.svg.styles.iidm.TopologicalStyleProvider;
import javafx.beans.property.*;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
Expand Down Expand Up @@ -44,7 +44,6 @@ public String toString() {
};
}
}

private static final String UNKNOWN_ITEM = "???";

// LayoutParameters
Expand Down Expand Up @@ -73,6 +72,16 @@ public String toString() {
private final Map<String, SubstationLayoutFactory> nameToSubstationLayoutFactoryMap = new TreeMap<>(); // ordered
private final ObservableList<SubstationLayoutFactory> substationLayouts = FXCollections.observableArrayList();
private final ObjectProperty<SubstationLayoutFactory> currentSubstationLayoutFactory = new SimpleObjectProperty<>();
// Zone layout provider
private static final String HORIZONTAL_ZONE_LAYOUT = "Horizontal";
private static final String VERTICAL_ZONE_LAYOUT = "Vertical";
private static final String MATRIX_ZONE_LAYOUT = "Matrix";
private String[][] matrix = {{}};

private MatrixZoneLayoutFactory matrixZoneLayoutFactory = new MatrixZoneLayoutFactory(this.matrix);
private final Map<String, ZoneLayoutFactory> nameToZoneLayoutFactoryMap = new TreeMap<>(); // ordered
private final ObservableList<ZoneLayoutFactory> zoneLayouts = FXCollections.observableArrayList();
private final ObjectProperty<ZoneLayoutFactory> currentZoneLayoutFactory = new SimpleObjectProperty<>();

// CGMES-DL names
private final ObservableList<String> cgmesDLDiagramNames = FXCollections.observableArrayList();
Expand All @@ -81,6 +90,7 @@ public String toString() {
public SingleLineDiagramModel(// Providers
ReadOnlyObjectProperty<ComponentLibrary> componentLibrary,
ReadOnlyObjectProperty<SubstationLayoutFactory> substationLayoutFactory,
ReadOnlyObjectProperty<ZoneLayoutFactory> zoneLayoutFactory,
ReadOnlyObjectProperty<String> cgmesDLDiagramName,
// Styles
BooleanProperty basicStyleProvider,
Expand Down Expand Up @@ -129,6 +139,7 @@ public SingleLineDiagramModel(// Providers
// Providers
this.currentComponentLibrary.bind(componentLibrary);
this.currentSubstationLayoutFactory.bind(substationLayoutFactory);
this.currentZoneLayoutFactory.bind(zoneLayoutFactory);
this.currentCgmesDLDiagramName.bind(cgmesDLDiagramName);

// Styles
Expand Down Expand Up @@ -175,13 +186,19 @@ public SingleLineDiagramModel(// Providers
}

public void initProviders() {
// zoneLayouts
nameToZoneLayoutFactoryMap.put(HORIZONTAL_ZONE_LAYOUT, new HorizontalZoneLayoutFactory());
nameToZoneLayoutFactoryMap.put(VERTICAL_ZONE_LAYOUT, new VerticalZoneLayoutFactory());
nameToZoneLayoutFactoryMap.put(MATRIX_ZONE_LAYOUT, this.matrixZoneLayoutFactory);

// SubstationLayouts
nameToSubstationLayoutFactoryMap.put(HORIZONTAL_SUBSTATION_LAYOUT, new HorizontalSubstationLayoutFactory());
nameToSubstationLayoutFactoryMap.put(VERTICAL_SUBSTATION_LAYOUT, new VerticalSubstationLayoutFactory());

// Set all providers list
componentLibraries.setAll(ComponentLibrary.findAll());
substationLayouts.setAll(nameToSubstationLayoutFactoryMap.values());
zoneLayouts.setAll(nameToZoneLayoutFactoryMap.values());
}

public void updateFrom(Network network) {
Expand Down Expand Up @@ -248,6 +265,10 @@ public SubstationLayoutFactory getSubstationLayoutFactory() {
return currentSubstationLayoutFactory.get();
}

public ZoneLayoutFactory getZoneLayoutFactory() {
return currentZoneLayoutFactory.get();
}

public ObservableList<ComponentLibrary> getComponentLibraries() {
return componentLibraries;
}
Expand All @@ -256,6 +277,10 @@ public ObservableList<SubstationLayoutFactory> getSubstationLayouts() {
return substationLayouts;
}

public ObservableList<ZoneLayoutFactory> getZoneLayouts() {
return zoneLayouts;
}

public ObservableList<String> getCgmesDLDiagramNames() {
return cgmesDLDiagramNames;
}
Expand Down Expand Up @@ -288,4 +313,27 @@ public SubstationLayoutFactory fromString(String item) {
}
};
}

public StringConverter<ZoneLayoutFactory> getZoneLayoutStringConverter() {
return new StringConverter<>() {
@Override
public String toString(ZoneLayoutFactory object) {
Optional<String> label = nameToZoneLayoutFactoryMap.keySet().stream().filter(name -> nameToZoneLayoutFactoryMap.get(name) == object).findFirst();
return label.orElse(UNKNOWN_ITEM);
}

@Override
public ZoneLayoutFactory fromString(String item) {
return nameToZoneLayoutFactoryMap.get(item);
}
};
}

public void setMatrix(String[][] matrix) {
this.matrix = matrix;
}

public String[][] getMatrix() {
return matrix;
}
}
Loading
Loading