diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/Messages.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/Messages.java index 6ae1f35e8f..d5c1f826fd 100644 --- a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/Messages.java +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/Messages.java @@ -208,6 +208,8 @@ public class Messages LogScale, Miscellaneous, Model_Disconnected, + MoveAxisToTheLeft, + MoveAxisToTheRight, MoveItemDown, MoveItemUp, Name, diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/model/Model.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/model/Model.java index 0de100615d..a47f544fa9 100644 --- a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/model/Model.java +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/model/Model.java @@ -395,6 +395,39 @@ public void removeAxis(final AxisConfig axis) fireAxisChangedEvent(Optional.empty()); } + public void exchangeAxes(int i, int j) { + int lowerIndex, higherIndex; + if (i == j) { + return; + } + else if (j < i) { + lowerIndex = j; + higherIndex = i; + } + else { + lowerIndex = i; + higherIndex = j; + } + var lowerIndexAxis = getAxis(lowerIndex); + var higherIndexAxis = getAxis(higherIndex); + + axes.remove(lowerIndexAxis); + axes.remove(higherIndexAxis); + + axes.add(lowerIndex, higherIndexAxis); + axes.add(higherIndex, lowerIndexAxis); + + fireAxisChangedEvent(Optional.of(lowerIndexAxis)); + fireAxisChangedEvent(Optional.of(higherIndexAxis)); + fireAxisChangedEvent(Optional.empty()); // Updates the order of the axes in the UI under the "Value Axes" tab + + for (ModelItem item : items) { + if (item.getAxis() == lowerIndexAxis || item.getAxis() == higherIndexAxis) { + item.fireItemLookChanged(); // Prevents the "Axis" UI-setting (under the "Traces" tab) from sometimes not displaying in the UI when moving axes. + } + } + }; + /** @return How should plot rescale after archived data arrived? */ public ArchiveRescale getArchiveRescale() { diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/Perspective.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/Perspective.java index f0c53d426d..71e4804cdb 100644 --- a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/Perspective.java +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/Perspective.java @@ -7,17 +7,20 @@ ******************************************************************************/ package org.csstudio.trends.databrowser3.ui; -import static org.csstudio.trends.databrowser3.Activator.logger; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.logging.Level; -import java.util.prefs.BackingStoreException; -import java.util.prefs.Preferences; -import java.util.stream.Collectors; - +import javafx.application.Platform; +import javafx.collections.ObservableList; +import javafx.geometry.Orientation; +import javafx.scene.Node; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.MenuItem; +import javafx.scene.control.SeparatorMenuItem; +import javafx.scene.control.SplitPane; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.image.ImageView; +import javafx.scene.input.Dragboard; +import javafx.scene.input.TransferMode; +import org.csstudio.javafx.rtplot.internal.YAxisImpl; import org.csstudio.trends.databrowser3.Activator; import org.csstudio.trends.databrowser3.Messages; import org.csstudio.trends.databrowser3.imports.SampleImportAction; @@ -29,6 +32,9 @@ import org.csstudio.trends.databrowser3.ui.plot.ModelBasedPlot; import org.csstudio.trends.databrowser3.ui.plot.PlotListener; import org.csstudio.trends.databrowser3.ui.properties.AddPVorFormulaMenuItem; +import org.csstudio.trends.databrowser3.ui.properties.DeleteAxes; +import org.csstudio.trends.databrowser3.ui.properties.MoveAxisToTheLeft; +import org.csstudio.trends.databrowser3.ui.properties.MoveAxisToTheRight; import org.csstudio.trends.databrowser3.ui.properties.PropertyPanel; import org.csstudio.trends.databrowser3.ui.properties.RemoveUnusedAxes; import org.csstudio.trends.databrowser3.ui.sampleview.SampleView; @@ -45,19 +51,16 @@ import org.phoebus.ui.spi.ContextMenuEntry; import org.phoebus.ui.undo.UndoableActionManager; -import javafx.application.Platform; -import javafx.collections.ObservableList; -import javafx.geometry.Orientation; -import javafx.scene.Node; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.MenuItem; -import javafx.scene.control.SeparatorMenuItem; -import javafx.scene.control.SplitPane; -import javafx.scene.control.Tab; -import javafx.scene.control.TabPane; -import javafx.scene.image.ImageView; -import javafx.scene.input.Dragboard; -import javafx.scene.input.TransferMode; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; +import java.util.stream.Collectors; + +import static org.csstudio.trends.databrowser3.Activator.logger; /** Combined layout of all data browser components * @author Kay Kasemir @@ -216,11 +219,50 @@ private void createContextMenu() items.add(menuItem); }); - if (model.getEmptyAxis().isPresent()) { - items.add(new SeparatorMenuItem()); - items.add(new RemoveUnusedAxes(model, undo)); + boolean separatorForAxisOptionsAdded = false; + + if (model.getEmptyAxis().isPresent()) + { + items.add(new SeparatorMenuItem()); + separatorForAxisOptionsAdded = true; + items.add(new RemoveUnusedAxes(model, undo)); + } + + var yAxes = plot.getPlot().getYAxes(); + int numberOfYAxes = yAxes.size(); + + for (int i=0; i) { + YAxisImpl yAxisImpl = (YAxisImpl) yAxis; + + var region = yAxisImpl.getBounds(); + + var axisX1 = region.x; + var axisX2 = region.x + region.width; + + var sceneX = event.getX(); + if (sceneX >= axisX1 && sceneX <= axisX2) { + if (!separatorForAxisOptionsAdded) { + items.add(new SeparatorMenuItem()); + separatorForAxisOptionsAdded = true; + } + + if (model.getFirstItemOnAxis(model.getAxes().get(i)) == null) { + // Axis is empty + items.add(new DeleteAxes(this, model, undo, Arrays.asList(model.getAxes().get(i)))); + } + + MenuItem moveAxisToTheLeft = new MoveAxisToTheLeft(model, undo, i); + items.add(moveAxisToTheLeft); + MenuItem moveAxisToTheRight = new MoveAxisToTheRight(model, undo, i); + items.add(moveAxisToTheRight); + } + } + } } + items.addAll(new SeparatorMenuItem(), show_search, show_properties, show_export, show_samples, show_waveform, refresh); menu.show(getScene().getWindow(), event.getScreenX(), event.getScreenY()); diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/AxesTab.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/AxesTab.java index 901d4c67fd..bf48b0d73f 100644 --- a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/AxesTab.java +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/AxesTab.java @@ -272,6 +272,12 @@ private void createContextMenu() if (selection.size() > 0) items.add(new DeleteAxes(axes_table, model, undo, selection)); + if (selection.size() == 1) { + int index = axes_table.getItems().indexOf(selection.get(0)); + items.add(new MoveAxisToTheLeft(model, undo, index)); + items.add(new MoveAxisToTheRight(model, undo, index)); + } + if (model.getEmptyAxis().isPresent()) items.add(new RemoveUnusedAxes(model, undo)); diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/ExchangeAxesUndoableAction.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/ExchangeAxesUndoableAction.java new file mode 100644 index 0000000000..888987aa14 --- /dev/null +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/ExchangeAxesUndoableAction.java @@ -0,0 +1,37 @@ +package org.csstudio.trends.databrowser3.ui.properties; + +import org.csstudio.trends.databrowser3.model.Model; +import org.phoebus.ui.undo.UndoableAction; + +public class ExchangeAxesUndoableAction extends UndoableAction { + Model model; + int axisIndex1; + int axisIndex2; + + /** + * @param name Name used to show action in undo/redo UI + * @param model Data Browser model containing the axes whose positions to exchange + * @param axisIndex1 Index of the first of the axes whose positions to exchange + * @param axisIndex2 Index of the second of the axes whose positions to exchange + */ + public ExchangeAxesUndoableAction(String name, + Model model, + int axisIndex1, + int axisIndex2) { + super(name); + this.model = model; + this.axisIndex1 = axisIndex1; + this.axisIndex2 = axisIndex2; + } + + @Override + public void run() { + model.exchangeAxes(axisIndex1, axisIndex2); + + } + + @Override + public void undo() { + model.exchangeAxes(axisIndex2, axisIndex1); + } +} \ No newline at end of file diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/MoveAxisToTheLeft.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/MoveAxisToTheLeft.java new file mode 100644 index 0000000000..77885b5590 --- /dev/null +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/MoveAxisToTheLeft.java @@ -0,0 +1,64 @@ +package org.csstudio.trends.databrowser3.ui.properties; + +import javafx.scene.control.MenuItem; +import org.csstudio.trends.databrowser3.Activator; +import org.csstudio.trends.databrowser3.Messages; +import org.csstudio.trends.databrowser3.model.Model; +import org.phoebus.ui.undo.UndoableAction; +import org.phoebus.ui.undo.UndoableActionManager; + +import java.util.stream.Collectors; + +/** Action to move an axis to the left + */ +@SuppressWarnings("nls") +public class MoveAxisToTheLeft extends MenuItem +{ + /** @param model Model + * @param undoableActionManager Undo manager + * @param axisToMoveToTheLeft_index Index of axis to move to the left + */ + public MoveAxisToTheLeft(Model model, + UndoableActionManager undoableActionManager, + int axisToMoveToTheLeft_index) + { + super(Messages.MoveAxisToTheLeft, Activator.getIcon("left")); + + var axisToMoveToTheLeft = model.getAxes().get(axisToMoveToTheLeft_index); + + int axisIndex1, axisIndex2; + + var allAxes = model.getAxes(); + + if (!axisToMoveToTheLeft.isOnRight()) { + // Axis to move to the left is located on the left side of the graph + var allAxesOnTheLeft = allAxes.stream().filter(axis -> !axis.isOnRight()).collect(Collectors.toList()); + int axisToMoveToTheLeft_index_allAxesOnTheLeft = allAxesOnTheLeft.indexOf(axisToMoveToTheLeft); + if (axisToMoveToTheLeft_index_allAxesOnTheLeft > 0) { + var axisOnTheLeft = allAxesOnTheLeft.get(axisToMoveToTheLeft_index_allAxesOnTheLeft - 1); + axisIndex1 = allAxes.indexOf(axisOnTheLeft); + axisIndex2 = axisToMoveToTheLeft_index; + UndoableAction moveAxisToTheLeft = new ExchangeAxesUndoableAction(Messages.MoveAxisToTheLeft, + model, + axisIndex1, + axisIndex2); + setOnAction(actionEvent -> undoableActionManager.execute(moveAxisToTheLeft)); + } + } + else { + // Axis to move to the left is located on the right side of the graph + var allAxesOnTheRight = allAxes.stream().filter(axis -> axis.isOnRight()).collect(Collectors.toList()); + int axisToMoveToTheLeft_index_allAxesOnTheRight = allAxesOnTheRight.indexOf(axisToMoveToTheLeft); + if (axisToMoveToTheLeft_index_allAxesOnTheRight < allAxesOnTheRight.size() - 1) { + var axisOnTheLeft = allAxesOnTheRight.get(axisToMoveToTheLeft_index_allAxesOnTheRight + 1); // On the right side of the graph, axes are stored in "opposite" relative ordering + axisIndex1 = axisToMoveToTheLeft_index; + axisIndex2 = allAxes.indexOf(axisOnTheLeft); + UndoableAction moveAxisToTheLeft = new ExchangeAxesUndoableAction("Move Axis to the Left", + model, + axisIndex1, + axisIndex2); + setOnAction(actionEvent -> undoableActionManager.execute(moveAxisToTheLeft)); + } + } + } +} diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/MoveAxisToTheRight.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/MoveAxisToTheRight.java new file mode 100644 index 0000000000..a3082c431c --- /dev/null +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/properties/MoveAxisToTheRight.java @@ -0,0 +1,64 @@ +package org.csstudio.trends.databrowser3.ui.properties; + +import javafx.scene.control.MenuItem; +import org.csstudio.trends.databrowser3.Activator; +import org.csstudio.trends.databrowser3.Messages; +import org.csstudio.trends.databrowser3.model.Model; +import org.phoebus.ui.undo.UndoableAction; +import org.phoebus.ui.undo.UndoableActionManager; + +import java.util.stream.Collectors; + +/** Action to move an axis to the right + */ +@SuppressWarnings("nls") +public class MoveAxisToTheRight extends MenuItem +{ + /** @param model Model + * @param undoableActionManager Undo manager + * @param axisToMoveToTheRight_index Index of axis to move to the right + */ + public MoveAxisToTheRight(Model model, + UndoableActionManager undoableActionManager, + int axisToMoveToTheRight_index) + { + super(Messages.MoveAxisToTheRight, Activator.getIcon("right")); + + var axisToMoveToTheRight = model.getAxes().get(axisToMoveToTheRight_index); + + int axisIndex1, axisIndex2; + + var allAxes = model.getAxes(); + + if (!axisToMoveToTheRight.isOnRight()) { + // Axis to move to the right is located on the left side of the graph + var allAxesOnTheLeft = allAxes.stream().filter(axis -> !axis.isOnRight()).collect(Collectors.toList()); + int axisToMoveToTheRight_index_allAxesOnTheLeft = allAxesOnTheLeft.indexOf(axisToMoveToTheRight); + if (axisToMoveToTheRight_index_allAxesOnTheLeft < allAxesOnTheLeft.size() - 1) { + var axisOnTheRight = allAxesOnTheLeft.get(axisToMoveToTheRight_index_allAxesOnTheLeft + 1); + axisIndex1 = axisToMoveToTheRight_index; + axisIndex2 = allAxes.indexOf(axisOnTheRight); + UndoableAction moveAxisToTheRight = new ExchangeAxesUndoableAction("Move Axis to the Right", + model, + axisIndex1, + axisIndex2); + setOnAction(actionEvent -> undoableActionManager.execute(moveAxisToTheRight)); + } + } + else { + // Axis to move to the right is located on the right side of the graph + var allAxesOnTheRight = allAxes.stream().filter(axis -> axis.isOnRight()).collect(Collectors.toList()); + int axisToMoveToTheRight_index_allAxesOnTheRight = allAxesOnTheRight.indexOf(axisToMoveToTheRight); + if (axisToMoveToTheRight_index_allAxesOnTheRight > 0) { + var axisOnTheRight = allAxesOnTheRight.get(axisToMoveToTheRight_index_allAxesOnTheRight - 1); // On the right side of the graph, axes are stored in "opposite" relative ordering + axisIndex1 = allAxes.indexOf(axisOnTheRight); + axisIndex2 = axisToMoveToTheRight_index; + UndoableAction moveAxisToTheRight = new ExchangeAxesUndoableAction(Messages.MoveAxisToTheRight, + model, + axisIndex1, + axisIndex2); + setOnAction(actionEvent -> undoableActionManager.execute(moveAxisToTheRight)); + } + } + } +} diff --git a/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages.properties b/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages.properties index da2e1c39eb..f5f6059695 100644 --- a/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages.properties +++ b/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages.properties @@ -188,6 +188,8 @@ LiveSampleBufferSize=Buffer Size LogScale=Log. Scale Miscellaneous=Misc. Model_Disconnected=Disconnected +MoveAxisToTheLeft=Move Axis to the Left +MoveAxisToTheRight=Move Axis to the Right MoveItemDown=Move Down MoveItemUp=Move Up Name=Name