This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new 1c27968a36 Add support for resizing notes #6056 (#6134)
1c27968a36 is described below
commit 1c27968a36a3081c900b4bda5730f87b13b9d0c5
Author: Nicolas Adment <[email protected]>
AuthorDate: Sun Dec 7 14:18:24 2025 +0100
Add support for resizing notes #6056 (#6134)
- Improve click handling by layering interactions (area owners, hops,
notes, background).
- Clearer cursor changes during operations.
- The viewport is now on the top layer.
- Fix `previousTransformLocations` with `previousActionLocations` for
better naming consistency.
- Add gui action to bring a note to front or send to back
- Add i18n to pipeline contextual action categories
---
.../main/java/org/apache/hop/core/NotePadMeta.java | 41 +-
.../java/org/apache/hop/core/gui/BasePainter.java | 128 +++---
.../java/org/apache/hop/workflow/WorkflowMeta.java | 8 +-
.../main/java/org/apache/hop/ui/core/PropsUi.java | 34 +-
.../apache/hop/ui/hopgui/dialog/NotePadDialog.java | 1 +
.../hopgui/file/pipeline/HopGuiPipelineGraph.java | 354 +++++++++------
.../ui/hopgui/file/shared/HopGuiAbstractGraph.java | 194 ++++++++-
.../hopgui/file/workflow/HopGuiWorkflowGraph.java | 474 +++++++++++++--------
.../perspective/execution/DragViewZoomBase.java | 28 +-
.../pipeline/messages/messages_en_US.properties | 9 +
.../workflow/messages/messages_en_US.properties | 5 +
ui/src/main/resources/ui/images/bring-to-front.svg | 12 +
ui/src/main/resources/ui/images/send-to-back.svg | 14 +
13 files changed, 876 insertions(+), 426 deletions(-)
diff --git a/engine/src/main/java/org/apache/hop/core/NotePadMeta.java
b/engine/src/main/java/org/apache/hop/core/NotePadMeta.java
index 24679dc72c..e6d11bb2ac 100644
--- a/engine/src/main/java/org/apache/hop/core/NotePadMeta.java
+++ b/engine/src/main/java/org/apache/hop/core/NotePadMeta.java
@@ -17,6 +17,8 @@
package org.apache.hop.core;
+import lombok.Getter;
+import lombok.Setter;
import org.apache.hop.core.exception.HopXmlException;
import org.apache.hop.core.gui.IGuiPosition;
import org.apache.hop.core.gui.IGuiSize;
@@ -89,6 +91,9 @@ public class NotePadMeta implements Cloneable, IGuiPosition,
IGuiSize {
@HopMetadataProperty public int width;
@HopMetadataProperty public int height;
+ @Getter @Setter private int minimumWidth;
+ @Getter @Setter private int minimumHeight;
+
private boolean selected;
private boolean changed;
@@ -115,11 +120,11 @@ public class NotePadMeta implements Cloneable,
IGuiPosition, IGuiSize {
}
public NotePadMeta(
- String n,
- int xl,
- int yl,
- int w,
- int h,
+ String note,
+ int x,
+ int y,
+ int width,
+ int height,
String fontName,
int fontSize,
boolean fontBold,
@@ -127,16 +132,16 @@ public class NotePadMeta implements Cloneable,
IGuiPosition, IGuiSize {
int fontColorRed,
int fontColorGreen,
int fontColorBlue,
- int backGrounColorRed,
- int backGrounColorGreen,
- int backGrounColorBlue,
+ int backGroundColorRed,
+ int backGroundColorGreen,
+ int backGroundColorBlue,
int borderColorRed,
int borderColorGreen,
int borderColorBlue) {
- this.note = n;
- this.location = new Point(xl, yl);
- this.width = w;
- this.height = h;
+ this.note = note;
+ this.location = new Point(x, y);
+ this.width = width;
+ this.height = height;
this.selected = false;
this.fontName = fontName;
this.fontSize = fontSize;
@@ -147,9 +152,9 @@ public class NotePadMeta implements Cloneable,
IGuiPosition, IGuiSize {
this.fontColorGreen = fontColorGreen;
this.fontColorBlue = fontColorBlue;
// background color
- this.backGroundColorRed = backGrounColorRed;
- this.backGroundColorGreen = backGrounColorGreen;
- this.backGroundColorBlue = backGrounColorBlue;
+ this.backGroundColorRed = backGroundColorRed;
+ this.backGroundColorGreen = backGroundColorGreen;
+ this.backGroundColorBlue = backGroundColorBlue;
// border color
this.borderColorRed = borderColorRed;
this.borderColorGreen = borderColorGreen;
@@ -354,6 +359,9 @@ public class NotePadMeta implements Cloneable,
IGuiPosition, IGuiSize {
*/
@Override
public void setHeight(int height) {
+ if (this.height != height) {
+ setChanged();
+ }
this.height = height;
}
@@ -370,6 +378,9 @@ public class NotePadMeta implements Cloneable,
IGuiPosition, IGuiSize {
*/
@Override
public void setWidth(int width) {
+ if (this.width != width) {
+ setChanged();
+ }
this.width = width;
}
diff --git a/engine/src/main/java/org/apache/hop/core/gui/BasePainter.java
b/engine/src/main/java/org/apache/hop/core/gui/BasePainter.java
index 62dd45e487..ef312afca3 100644
--- a/engine/src/main/java/org/apache/hop/core/gui/BasePainter.java
+++ b/engine/src/main/java/org/apache/hop/core/gui/BasePainter.java
@@ -127,102 +127,90 @@ public abstract class BasePainter<Hop extends
BaseHopMeta<?>, Part extends IBase
}
public static EImage getStreamIconImage(StreamIcon streamIcon, boolean
enabled) {
- switch (streamIcon) {
- case TRUE:
- return (enabled) ? EImage.TRUE : EImage.TRUE_DISABLED;
- case FALSE:
- return (enabled) ? EImage.FALSE : EImage.FALSE_DISABLED;
- case ERROR:
- return (enabled) ? EImage.ERROR : EImage.ERROR_DISABLED;
- case INFO:
- return (enabled) ? EImage.INFO : EImage.INFO_DISABLED;
- case TARGET:
- return (enabled) ? EImage.TARGET : EImage.TARGET_DISABLED;
- case INPUT:
- return EImage.INPUT;
- case OUTPUT:
- return EImage.OUTPUT;
- default:
- return EImage.ARROW_DEFAULT;
+ return switch (streamIcon) {
+ case TRUE -> (enabled) ? EImage.TRUE : EImage.TRUE_DISABLED;
+ case FALSE -> (enabled) ? EImage.FALSE : EImage.FALSE_DISABLED;
+ case ERROR -> (enabled) ? EImage.ERROR : EImage.ERROR_DISABLED;
+ case INFO -> (enabled) ? EImage.INFO : EImage.INFO_DISABLED;
+ case TARGET -> (enabled) ? EImage.TARGET : EImage.TARGET_DISABLED;
+ case INPUT -> EImage.INPUT;
+ case OUTPUT -> EImage.OUTPUT;
+ default -> EImage.ARROW_DEFAULT;
+ };
+ }
+
+ protected Point calculateMinimumSize(NotePadMeta note) {
+ if (Utils.isEmpty(note.getNote())) {
+ return new Point(20, 20); // Empty note
}
+
+ int fontHeight;
+ if (note.getFontSize() > 0) {
+ fontHeight = note.getFontSize();
+ } else {
+ fontHeight = noteFontHeight;
+ }
+ gc.setFont(
+ Const.NVL(note.getFontName(), noteFontName),
+ (int) ((double) fontHeight / zoomFactor),
+ note.isFontBold(),
+ note.isFontItalic());
+
+ Point size = gc.textExtent(note.getNote());
+ size.x += 2 * Const.NOTE_MARGIN;
+ size.y += 2 * Const.NOTE_MARGIN;
+
+ return size;
}
- protected void drawNote(NotePadMeta notePadMeta) {
- if (notePadMeta.isSelected()) {
+ protected void drawNote(NotePadMeta noteMeta) {
+ if (noteMeta.isSelected()) {
gc.setLineWidth(2);
} else {
gc.setLineWidth(1);
}
- Point ext;
- if (Utils.isEmpty(notePadMeta.getNote())) {
- ext = new Point(10, 10); // Empty note
- } else {
+ Point minimumSize = this.calculateMinimumSize(noteMeta);
- int fontHeight;
- if (notePadMeta.getFontSize() > 0) {
- fontHeight = notePadMeta.getFontSize();
- } else {
- fontHeight = noteFontHeight;
- }
- gc.setFont(
- Const.NVL(notePadMeta.getFontName(), noteFontName),
- (int) ((double) fontHeight / zoomFactor),
- notePadMeta.isFontBold(),
- notePadMeta.isFontItalic());
+ // Cache the minimum size for resize operation
+ noteMeta.setMinimumWidth(minimumSize.x);
+ noteMeta.setMinimumHeight(minimumSize.y);
- ext = gc.textExtent(notePadMeta.getNote());
- }
- Point p = new Point(ext.x, ext.y);
- Point loc = notePadMeta.getLocation();
+ Point loc = noteMeta.getLocation();
Point note = real2screen(loc.x, loc.y);
- int margin = Const.NOTE_MARGIN;
- p.x += 2 * margin;
- p.y += 2 * margin;
- int width = notePadMeta.width;
- int height = notePadMeta.height;
- if (p.x > width) {
- width = p.x;
+
+ int width = noteMeta.width;
+ int height = noteMeta.height;
+ if (minimumSize.x > width) {
+ width = minimumSize.x;
}
- if (p.y > height) {
- height = p.y;
+ if (minimumSize.y > height) {
+ height = minimumSize.y;
}
-
Rectangle noteShape = new Rectangle(note.x, note.y, width, height);
gc.setBackground(
- notePadMeta.getBackGroundColorRed(),
- notePadMeta.getBackGroundColorGreen(),
- notePadMeta.getBackGroundColorBlue());
+ noteMeta.getBackGroundColorRed(),
+ noteMeta.getBackGroundColorGreen(),
+ noteMeta.getBackGroundColorBlue());
gc.setForeground(
- notePadMeta.getBorderColorRed(),
- notePadMeta.getBorderColorGreen(),
- notePadMeta.getBorderColorBlue());
+ noteMeta.getBorderColorRed(),
+ noteMeta.getBorderColorGreen(),
+ noteMeta.getBorderColorBlue());
// Radius is half the font height
//
- int radius = (int) Math.round(zoomFactor * notePadMeta.getFontSize() / 2);
+ int radius = (int) Math.round(zoomFactor * 8);
gc.fillRoundRectangle(
noteShape.x, noteShape.y, noteShape.width, noteShape.height, radius,
radius);
gc.drawRoundRectangle(
noteShape.x, noteShape.y, noteShape.width, noteShape.height, radius,
radius);
- if (!Utils.isEmpty(notePadMeta.getNote())) {
+ if (!Utils.isEmpty(noteMeta.getNote())) {
gc.setForeground(
- notePadMeta.getFontColorRed(),
- notePadMeta.getFontColorGreen(),
- notePadMeta.getFontColorBlue());
- gc.drawText(notePadMeta.getNote(), note.x + margin, note.y + margin,
true);
- }
-
- notePadMeta.width = width; // Save for the "mouse" later on...
- notePadMeta.height = height;
-
- if (notePadMeta.isSelected()) {
- gc.setLineWidth(1);
- } else {
- gc.setLineWidth(2);
+ noteMeta.getFontColorRed(), noteMeta.getFontColorGreen(),
noteMeta.getFontColorBlue());
+ gc.drawText(noteMeta.getNote(), note.x + Const.NOTE_MARGIN, note.y +
Const.NOTE_MARGIN, true);
}
// Add to the list of areas...
@@ -236,7 +224,7 @@ public abstract class BasePainter<Hop extends
BaseHopMeta<?>, Part extends IBase
noteShape.height,
offset,
subject,
- notePadMeta));
+ noteMeta));
}
protected Point real2screen(int x, int y) {
diff --git a/engine/src/main/java/org/apache/hop/workflow/WorkflowMeta.java
b/engine/src/main/java/org/apache/hop/workflow/WorkflowMeta.java
index fd69ee1021..54ea897961 100644
--- a/engine/src/main/java/org/apache/hop/workflow/WorkflowMeta.java
+++ b/engine/src/main/java/org/apache/hop/workflow/WorkflowMeta.java
@@ -1278,9 +1278,9 @@ public class WorkflowMeta extends AbstractMeta
}
/**
- * Gets the selected locations.
+ * Gets the selected actions locations.
*
- * @return the selected locations
+ * @return the selected actions locations
*/
public Point[] getSelectedLocations() {
List<ActionMeta> actions = getSelectedActions();
@@ -1294,9 +1294,9 @@ public class WorkflowMeta extends AbstractMeta
}
/**
- * Get all the selected note locations
+ * Get all the selected notes locations
*
- * @return The selected transform and notes locations.
+ * @return The selected notes locations.
*/
public Point[] getSelectedNoteLocations() {
List<Point> points = new ArrayList<>();
diff --git a/ui/src/main/java/org/apache/hop/ui/core/PropsUi.java
b/ui/src/main/java/org/apache/hop/ui/core/PropsUi.java
index 9dc962af80..3b19e7dfac 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/PropsUi.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/PropsUi.java
@@ -23,6 +23,7 @@ import org.apache.commons.lang.StringUtils;
import org.apache.hop.core.Const;
import org.apache.hop.core.Props;
import org.apache.hop.core.gui.IGuiPosition;
+import org.apache.hop.core.gui.IGuiSize;
import org.apache.hop.core.gui.Point;
import org.apache.hop.core.logging.LogChannel;
import org.apache.hop.core.util.Utils;
@@ -907,8 +908,8 @@ public class PropsUi extends Props {
// Snap to grid...
//
return new Point(
- gridSize * Math.round((float) p.x / gridSize),
- gridSize * Math.round((float) p.y / gridSize));
+ gridSize * (int) Math.round((float) (p.x / gridSize)),
+ gridSize * (int) Math.round((float) (p.y / gridSize)));
} else {
// Normal draw
//
@@ -916,6 +917,35 @@ public class PropsUi extends Props {
}
}
+ /**
+ * Sets the size of a given GUI element, ensuring that the width and height
do not fall below a
+ * predefined minimum size. The size is adjusted to align with a grid
through calculation.
+ *
+ * @param element the GUI element whose size is to be set
+ * @param width the desired width of the element
+ * @param height the desired height of the element
+ */
+ public static void setSize(IGuiSize element, int width, int height) {
+
+ if (width < ConstUi.NOTE_MIN_SIZE) {
+ width = ConstUi.NOTE_MIN_SIZE;
+ }
+ if (height < ConstUi.NOTE_MIN_SIZE) {
+ height = ConstUi.NOTE_MIN_SIZE;
+ }
+ int gridSize = PropsUi.getInstance().getCanvasGridSize();
+ if (gridSize > 1) {
+ int w = width / gridSize;
+ if (width % gridSize > 0) w += 1;
+ int h = height / gridSize;
+ if (height % gridSize > 0) h += 1;
+ width = gridSize * w;
+ height = gridSize * h;
+ }
+ element.setWidth(width);
+ element.setHeight(height);
+ }
+
public boolean isIndicateSlowPipelineTransformsEnabled() {
String indicate = getProperty(STRING_INDICATE_SLOW_PIPELINE_TRANSFORMS,
"Y");
return YES.equalsIgnoreCase(indicate);
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/dialog/NotePadDialog.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/dialog/NotePadDialog.java
index d742bd13c7..ca8a5c9c8d 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/dialog/NotePadDialog.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/dialog/NotePadDialog.java
@@ -252,6 +252,7 @@ public class NotePadDialog extends Dialog {
refreshTextNote();
}
});
+ PropsUi.setLook(wFontSize);
// Font bold?
Label wlFontBold = new Label(wNoteFontComp, SWT.RIGHT);
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraph.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraph.java
index e38f3269a0..877fc21084 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraph.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraph.java
@@ -569,7 +569,7 @@ public class HopGuiPipelineGraph extends HopGuiAbstractGraph
}
@Override
- public void mouseDoubleClick(MouseEvent e) {
+ public void mouseDoubleClick(MouseEvent event) {
if (!PropsUi.getInstance().useDoubleClick()) {
return;
@@ -578,7 +578,7 @@ public class HopGuiPipelineGraph extends HopGuiAbstractGraph
doubleClick = true;
clearSettings();
- Point real = screen2real(e.x, e.y);
+ Point real = screen2real(event.x, event.y);
// Hide the tooltip!
hideToolTips();
@@ -586,7 +586,8 @@ public class HopGuiPipelineGraph extends HopGuiAbstractGraph
AreaOwner areaOwner = getVisibleAreaOwner(real.x, real.y);
try {
- HopGuiPipelineGraphExtension ext = new
HopGuiPipelineGraphExtension(this, e, real, areaOwner);
+ HopGuiPipelineGraphExtension ext =
+ new HopGuiPipelineGraphExtension(this, event, real, areaOwner);
ExtensionPointHandler.callExtensionPoint(
LogChannel.GENERAL, variables,
HopExtensionPoint.PipelineGraphMouseDoubleClick.id, ext);
if (ext.isPreventingDefault()) {
@@ -599,7 +600,7 @@ public class HopGuiPipelineGraph extends HopGuiAbstractGraph
TransformMeta transformMeta = pipelineMeta.getTransform(real.x, real.y,
iconSize);
if (transformMeta != null) {
- if (e.button == 1) {
+ if (event.button == 1) {
editTransform(transformMeta);
} else {
editDescription(transformMeta);
@@ -633,21 +634,22 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
}
@Override
- public void mouseDown(MouseEvent e) {
+ public void mouseDown(MouseEvent event) {
if (EnvironmentUtils.getInstance().isWeb()) {
// RAP does not support certain mouse events.
- mouseHover(e);
+ mouseHover(event);
}
doubleClick = false;
mouseMovedSinceClick = false;
+ resize = null;
- boolean alt = (e.stateMask & SWT.ALT) != 0;
- boolean control = (e.stateMask & SWT.MOD1) != 0;
- boolean shift = (e.stateMask & SWT.SHIFT) != 0;
+ boolean alt = (event.stateMask & SWT.ALT) != 0;
+ boolean control = (event.stateMask & SWT.MOD1) != 0;
+ boolean shift = (event.stateMask & SWT.SHIFT) != 0;
- lastButton = e.button;
- Point real = screen2real(e.x, e.y);
+ Point real = screen2real(event.x, event.y);
lastClick = new Point(real.x, real.y);
+ lastButton = event.button;
// Hide the tooltip!
hideToolTips();
@@ -655,7 +657,8 @@ public class HopGuiPipelineGraph extends HopGuiAbstractGraph
AreaOwner areaOwner = getVisibleAreaOwner(real.x, real.y);
try {
- HopGuiPipelineGraphExtension ext = new
HopGuiPipelineGraphExtension(this, e, real, areaOwner);
+ HopGuiPipelineGraphExtension ext =
+ new HopGuiPipelineGraphExtension(this, event, real, areaOwner);
ExtensionPointHandler.callExtensionPoint(
LogChannel.GENERAL, variables,
HopExtensionPoint.PipelineGraphMouseDown.id, ext);
if (ext.isPreventingDefault()) {
@@ -665,14 +668,26 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
LogChannel.GENERAL.logError("Error calling PipelineGraphMouseDown
extension point", ex);
}
+ // Layer 0: See if we're dragging around the view-port over the pipeline
graph.
+ //
+ Point clickScreen = new Point(event.x, event.y);
+ if (setupDragViewPort(clickScreen)) {
+ return;
+ }
+
// A single left or middle click on one of the area owners...
//
+ boolean done = false;
+
+ // Layer 1: Click on an area owner except note (else if a note is present
in the background,
+ // you cannot click the hop link).
if (areaOwner != null && areaOwner.getAreaType() != null) {
switch (areaOwner.getAreaType()) {
case TRANSFORM_INFO_ICON:
// Click on the transform info icon means: Edit transformation
description
//
this.editDescription((TransformMeta) areaOwner.getOwner());
+ done = true;
break;
case HOP_INFO_ICON:
@@ -680,6 +695,7 @@ public class HopGuiPipelineGraph extends HopGuiAbstractGraph
//
pipelineTransformDelegate.editTransform(
pipelineMeta, (TransformMeta) areaOwner.getOwner());
+ done = true;
break;
case TRANSFORM_TARGET_HOP_ICON:
@@ -687,9 +703,11 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
//
pipelineTransformDelegate.editTransform(
pipelineMeta, (TransformMeta) areaOwner.getParent());
+ done = true;
break;
case HOP_COPY_ICON:
+ done = true;
break;
case HOP_ERROR_ICON:
@@ -697,6 +715,11 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
//
pipelineTransformDelegate.editTransformErrorHandling(
pipelineMeta, (TransformMeta) areaOwner.getParent());
+ done = true;
+ break;
+
+ case TRANSFORM_NAME:
+ done = true;
break;
case TRANSFORM_ICON:
@@ -707,7 +730,7 @@ public class HopGuiPipelineGraph extends HopGuiAbstractGraph
if (candidate != null && !OsHelper.isMac()) {
// Avoid duplicate pop-up for hop handling as candidate is never
null? */
- addCandidateAsHop(e.x, e.y);
+ addCandidateAsHop(event.x, event.y);
}
TransformMeta transformMeta = (TransformMeta) areaOwner.getOwner();
@@ -719,12 +742,12 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
// ALT-Click: edit error handling
//
- if (e.button == 1 && alt && transformMeta.supportsErrorHandling()) {
+ if (event.button == 1 && alt &&
transformMeta.supportsErrorHandling()) {
pipelineTransformDelegate.editTransformErrorHandling(pipelineMeta,
transformMeta);
return;
- } else if (e.button == 1 && startHopTransform != null &&
endHopTransform == null) {
+ } else if (event.button == 1 && startHopTransform != null &&
endHopTransform == null) {
candidate = new PipelineHopMeta(startHopTransform,
currentTransform);
- } else if (e.button == 2 || (e.button == 1 && shift)) {
+ } else if (event.button == 2 || (event.button == 1 && shift)) {
// SHIFT CLICK is start of drag to create a new hop
//
canvas.setData("mode", "hop");
@@ -744,37 +767,31 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
iconOffset = new Point(real.x - p.x, real.y - p.y);
}
redraw();
- break;
-
- case NOTE:
- currentNotePad = (NotePadMeta) areaOwner.getOwner();
- selectedNotes = pipelineMeta.getSelectedNotes();
- selectedNote = currentNotePad;
- Point loc = currentNotePad.getLocation();
-
- previousNoteLocations = pipelineMeta.getSelectedNoteLocations();
-
- noteOffset = new Point(real.x - loc.x, real.y - loc.y);
-
- redraw();
+ done = true;
break;
case TRANSFORM_COPIES_TEXT:
copies((TransformMeta) areaOwner.getOwner());
+ done = true;
break;
case TRANSFORM_DATA_SERVICE:
editProperties(pipelineMeta, hopGui, PipelineDialog.Tabs.EXTRA_TAB);
+ done = true;
break;
+
default:
break;
}
- } else {
+ }
+
+ // Layer 2: click on hop links between transforms
+ if (!done) {
// hop links between transforms are found searching by (x,y) coordinates.
PipelineHopMeta hop = findPipelineHop(real.x, real.y);
if (hop != null) {
// Delete hop with on click
- if (e.button == 1 && shift && control) {
+ if (event.button == 1 && shift && control) {
// Delete the hop
pipelineHopDelegate.delHop(pipelineMeta, hop);
updateGui();
@@ -782,7 +799,7 @@ public class HopGuiPipelineGraph extends HopGuiAbstractGraph
// User held control and clicked a hop between steps - We want to flip
the active state of
// the hop.
//
- else if (e.button == 2 || (e.button == 1 && control)) {
+ else if (event.button == 2 || (event.button == 1 && control)) {
hop.setEnabled(!hop.isEnabled());
updateGui();
} else {
@@ -790,38 +807,68 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
//
clickedPipelineHop = hop;
}
- } else {
- // If we're dragging a candidate hop around and click on the
background it simply needs to
- // go away.
- //
- if (startHopTransform != null) {
- startHopTransform = null;
- candidate = null;
- lastClick = null;
- avoidContextDialog = true;
- redraw();
- return;
- }
+ done = true;
+ }
+ }
- // Dragging on the background?
- // See if we're dragging around the view-port over the pipeline graph.
- //
- if (setupDragView(e.button, control, new Point(e.x, e.y))) {
- return;
- }
+ // Layer 3: click on a note
+ if (!done && areaOwner != null && areaOwner.getAreaType() ==
AreaOwner.AreaType.NOTE) {
+ currentNotePad = (NotePadMeta) areaOwner.getOwner();
+ selectedNotes = pipelineMeta.getSelectedNotes();
+ selectedNote = currentNotePad;
+ Point loc = currentNotePad.getLocation();
- // No area-owner & no hop means : background click:
- //
- canvas.setData("mode", "select");
- if (!control && e.button == 1) {
- selectionRegion = new org.apache.hop.core.gui.Rectangle(real.x,
real.y, 0, 0);
- }
- updateGui();
+ previousNoteLocations = pipelineMeta.getSelectedNoteLocations();
+
+ noteOffset = new Point(real.x - loc.x, real.y - loc.y);
+
+ resize = this.getResize(areaOwner.getArea(), real);
+ // Keep the original area of the resizing note
+ resizeArea =
+ new Rectangle(
+ currentNotePad.getLocation().x,
+ currentNotePad.getLocation().y,
+ currentNotePad.getWidth(),
+ currentNotePad.getHeight());
+
+ updateGui();
+ done = true;
+ }
+
+ // Layer 4: Click on the background of the graph
+ if (!done) {
+ // If we're dragging a candidate hop around and click on the background
it simply needs to
+ // go away.
+ //
+ if (startHopTransform != null) {
+ startHopTransform = null;
+ candidate = null;
+ lastClick = null;
+ avoidContextDialog = true;
+ redraw();
+ return;
}
+
+ // Click to drag the background
+ //
+ if (setupDragView(event.button, control, clickScreen)) {
+ return;
+ }
+
+ // Click to create a lasso
+ //
+ canvas.setData("mode", "select");
+ if (!control && event.button == 1) {
+ selectionRegion = new org.apache.hop.core.gui.Rectangle(real.x,
real.y, 0, 0);
+ // Change cursor when selecting a region
+ setCursor(getDisplay().getSystemCursor(SWT.CURSOR_CROSS));
+ }
+ updateGui();
}
+
if (EnvironmentUtils.getInstance().isWeb()) {
// RAP does not support certain mouse events.
- mouseMove(e);
+ mouseMove(event);
}
}
@@ -835,6 +882,8 @@ public class HopGuiPipelineGraph extends HopGuiAbstractGraph
@Override
public void mouseUp(MouseEvent e) {
+ resize = null;
+
// canvas.setData("mode", null); does not work.
canvas.setData("mode", "null");
@@ -850,7 +899,6 @@ public class HopGuiPipelineGraph extends HopGuiAbstractGraph
viewDrag = false;
viewPortNavigation = false;
viewPortStart = null;
- setCursor(null);
return;
}
@@ -1034,6 +1082,13 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
singleClick = true;
singleClickType = SingleClickType.Note;
singleClickNote = selectedNote;
+
+ // If the clicked note is not part of the current selection,
cancel the current
+ // selection
+ if (!selectedNote.isSelected()) {
+ pipelineMeta.unselectAll();
+ selectedNote.setSelected(true);
+ }
}
} else {
// Find out which Transforms & Notes are selected
@@ -1350,7 +1405,6 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
noInputTransform = null;
mouseMovedSinceClick = true;
boolean doRedraw = false;
- PipelineHopMeta hop = null;
// disable the tooltip
//
@@ -1372,6 +1426,13 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
//
lastMove = real;
+ // Resizing the current note
+ if (resize != null) {
+ resizeNote(selectedNote, real);
+ redraw();
+ return;
+ }
+
if (iconOffset == null) {
iconOffset = new Point(0, 0);
}
@@ -1385,12 +1446,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
// Moved over an area?
//
AreaOwner areaOwner = getVisibleAreaOwner(real.x, real.y);
-
- // Moved over an hop?
- //
- if (areaOwner == null) {
- hop = this.findPipelineHop(real.x, real.y);
- }
+ Resize resizeOver = resize;
try {
HopGuiPipelineGraphExtension ext =
@@ -1404,19 +1460,27 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
LogChannel.GENERAL.logError("Error calling PipelineGraphMouseMoved
extension point", ex);
}
- // Mouse over the name of the transform
- //
- if (!PropsUi.getInstance().useDoubleClick()) {
- if (areaOwner != null && areaOwner.getAreaType() ==
AreaType.TRANSFORM_NAME) {
- if (mouseOverName == null) {
- doRedraw = true;
- }
- mouseOverName = (String) areaOwner.getOwner();
- } else {
- if (mouseOverName != null) {
- doRedraw = true;
+ if (areaOwner != null) {
+ // Mouse over the name of the transform
+ //
+ if (!PropsUi.getInstance().useDoubleClick()) {
+ if (areaOwner.getAreaType() == AreaType.TRANSFORM_NAME) {
+ if (mouseOverName == null) {
+ doRedraw = true;
+ }
+ mouseOverName = (String) areaOwner.getOwner();
+ } else {
+ if (mouseOverName != null) {
+ doRedraw = true;
+ }
+ mouseOverName = null;
}
- mouseOverName = null;
+ }
+
+ // Mouse over a note
+ if (areaOwner.getAreaType() == AreaOwner.AreaType.NOTE) {
+ // Check if the mouse hovers over the border to resize
+ resizeOver = this.getResize(areaOwner.getArea(), real);
}
}
@@ -1538,9 +1602,9 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
}
}
- // Move around notes & transforms
+ // Move around notes and transforms
//
- if (selectedNote != null && lastButton == 1 && !shift) {
+ if (selectedNote != null && lastButton == 1 && !shift && resize == null) {
/*
* One or more notes are selected and moved around...
*
@@ -1555,19 +1619,15 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
}
Cursor cursor = null;
- // Change cursor when dragging view or view port
- if (viewDrag || viewPortNavigation) {
- cursor = getDisplay().getSystemCursor(SWT.CURSOR_SIZEALL);
- }
- // Change cursor when selecting a region
- else if (selectionRegion != null) {
- cursor = getDisplay().getSystemCursor(SWT.CURSOR_CROSS);
+ // Change the cursor when the mouse is on the resize edge of a note
+ if (resizeOver != null) {
+ cursor = getDisplay().getSystemCursor(resizeOver.getCursor());
}
- // Change cursor when hover an hop or an area that support hover
- else if (hop != null
- || (areaOwner != null
+ // Change cursor when the mouse is on a hop or an area that support
hovering
+ else if ((areaOwner != null
&& areaOwner.getAreaType() != null
- && areaOwner.getAreaType().isSupportHover())) {
+ && areaOwner.getAreaType().isSupportHover())
+ || this.findPipelineHop(real.x, real.y) != null) {
cursor = getDisplay().getSystemCursor(SWT.CURSOR_HAND);
}
setCursor(cursor);
@@ -2111,7 +2171,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::System.Button.Help",
tooltip = "i18n::System.Tooltip.Help",
image = "ui/images/help.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void openTransformHelp(HopGuiPipelineTransformContext context) {
IPlugin plugin =
@@ -2128,7 +2188,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.TransformAction.DetachTransform.Name",
tooltip =
"i18n::HopGuiPipelineGraph.TransformAction.DetachTransform.Tooltip",
image = "ui/images/hop-delete.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void detachTransform(HopGuiPipelineTransformContext context) {
TransformMeta transformMeta = context.getTransformMeta();
@@ -2194,7 +2254,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.TransformAction.EditTransform.Name",
tooltip =
"i18n::HopGuiPipelineGraph.TransformAction.EditTransform.Tooltip",
image = "ui/images/edit.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void editTransform(HopGuiPipelineTransformContext context) {
editTransform(context.getTransformMeta());
@@ -2212,7 +2272,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.TransformAction.EditDescription.Name",
tooltip =
"i18n::HopGuiPipelineGraph.TransformAction.EditDescription.Tooltip",
image = "ui/images/edit-description.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void editDescription(HopGuiPipelineTransformContext context) {
editDescription(context.getTransformMeta());
@@ -2225,7 +2285,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.TransformAction.DistributeRows.Name",
tooltip =
"i18n::HopGuiPipelineGraph.TransformAction.DistributeRows.Tooltip",
image = "ui/images/distribute.svg",
- category = "Data routing",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Routing.Text",
categoryOrder = "2")
public void setDistributes(HopGuiPipelineTransformContext context) {
context.getTransformMeta().setDistributes(true);
@@ -2240,7 +2300,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.TransformAction.CopyRows.Name",
tooltip = "i18n::HopGuiPipelineGraph.TransformAction.CopyRows.Tooltip",
image = "ui/images/copy-rows.svg",
- category = "Data routing",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Routing.Text",
categoryOrder = "2")
public void setCopies(HopGuiPipelineTransformContext context) {
context.getTransformMeta().setDistributes(false);
@@ -2295,7 +2355,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.TransformAction.SpecifyCopies.Name",
tooltip =
"i18n::HopGuiPipelineGraph.TransformAction.SpecifyCopies.Tooltip",
image = "ui/images/exponent.svg",
- category = "Data routing",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Routing.Text",
categoryOrder = "2")
public void copies(HopGuiPipelineTransformContext context) {
TransformMeta transformMeta = context.getTransformMeta();
@@ -2339,7 +2399,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.TransformAction.DeleteTransform.Name",
tooltip =
"i18n::HopGuiPipelineGraph.TransformAction.DeleteTransform.Tooltip",
image = "ui/images/delete.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void delTransform(HopGuiPipelineTransformContext context) {
delSelected(context.getTransformMeta());
@@ -2352,7 +2412,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name =
"i18n::HopGuiPipelineGraph.TransformAction.Transform.ShowInputFields.Name",
tooltip =
"i18n::HopGuiPipelineGraph.TransformAction.Transform.ShowInputFields.Tooltip",
image = "ui/images/input.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void fieldsBefore(HopGuiPipelineTransformContext context) {
selectedTransforms = null;
@@ -2366,7 +2426,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name =
"i18n::HopGuiPipelineGraph.TransformAction.Transform.ShowOutputFields.Name",
tooltip =
"i18n::HopGuiPipelineGraph.TransformAction.Transform.ShowOutputFields.Tooltip",
image = "ui/images/output.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void fieldsAfter(HopGuiPipelineTransformContext context) {
selectedTransforms = null;
@@ -2389,7 +2449,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.HopAction.EnableHop.Name",
tooltip = "i18n::HopGuiPipelineGraph.HopAction.EnableHop.Tooltip",
image = "ui/images/hop.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void enableHop(HopGuiPipelineHopContext context) {
PipelineHopMeta hop = context.getHopMeta();
@@ -2486,7 +2546,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.HopAction.DisableHop.Name",
tooltip = "i18n::HopGuiPipelineGraph.HopAction.DisableHop.Tooltip",
image = "ui/images/hop-disable.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void disableHop(HopGuiPipelineHopContext context) {
PipelineHopMeta hopMeta = context.getHopMeta();
@@ -2512,7 +2572,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.HopAction.DeleteHop.Name",
tooltip = "i18n::HopGuiPipelineGraph.HopAction.DeleteHop.Tooltip",
image = "ui/images/hop-delete.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void deleteHop(HopGuiPipelineHopContext context) {
pipelineHopDelegate.delHop(pipelineMeta, context.getHopMeta());
@@ -2534,7 +2594,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name =
"i18n::HopGuiPipelineGraph.HopAction.EnableBetweenSelectedTransforms.Name",
tooltip =
"i18n::HopGuiPipelineGraph.HopAction.EnableBetweenSelectedTransforms.Tooltip",
image = "ui/images/hop-enable-between-selected.svg",
- category = "Bulk",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Bulk.Text",
categoryOrder = "2")
public void enableHopsBetweenSelectedTransforms(final
HopGuiPipelineHopContext context) {
enableHopsBetweenSelectedTransforms(true);
@@ -2547,7 +2607,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name =
"i18n::HopGuiPipelineGraph.HopAction.DisableBetweenSelectedTransforms.Name",
tooltip =
"i18n::HopGuiPipelineGraph.HopAction.DisableBetweenSelectedTransforms.Tooltip",
image = "ui/images/hop-disable-between-selected.svg",
- category = "Bulk",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Bulk.Text",
categoryOrder = "2")
public void disableHopsBetweenSelectedTransforms(final
HopGuiPipelineHopContext context) {
enableHopsBetweenSelectedTransforms(false);
@@ -2596,7 +2656,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.HopAction.EnableDownstreamHop.Name",
tooltip =
"i18n::HopGuiPipelineGraph.HopAction.EnableDownstreamHop.Tooltip",
image = "ui/images/hop-enable-downstream.svg",
- category = "Bulk",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Bulk.Text",
categoryOrder = "2")
public void enableHopsDownstream(final HopGuiPipelineHopContext context) {
enableDisableHopsDownstream(context.getHopMeta(), true);
@@ -2609,7 +2669,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.HopAction.DisableDownstreamHop.Name",
tooltip =
"i18n::HopGuiPipelineGraph.HopAction.DisableDownstreamHop.Tooltip",
image = "ui/images/hop-disable-downstream.svg",
- category = "Bulk",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Bulk.Text",
categoryOrder = "2")
public void disableHopsDownstream(final HopGuiPipelineHopContext context) {
enableDisableHopsDownstream(context.getHopMeta(), false);
@@ -2669,7 +2729,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.HopAction.InsetTransform.Text",
tooltip = "i18n::HopGuiPipelineGraph.HopAction.InsetTransform.Tooltip",
image = "ui/images/add-item.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "13")
public void insertTransform(HopGuiPipelineHopContext context) {
// Build actions list
@@ -2728,7 +2788,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.NoteAction.EditNote.Name",
tooltip = "i18n::HopGuiPipelineGraph.NoteAction.EditNote.Tooltip",
image = "ui/images/edit.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void editNote(HopGuiPipelineNoteContext context) {
selectionRegion = null;
@@ -2742,7 +2802,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.NoteAction.DeleteNote.Name",
tooltip = "i18n::HopGuiPipelineGraph.NoteAction.DeleteNote.Tooltip",
image = "ui/images/delete.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void deleteNote(HopGuiPipelineNoteContext context) {
selectionRegion = null;
@@ -2762,7 +2822,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.NoteAction.CreateNote.Name",
tooltip = "i18n::HopGuiPipelineGraph.NoteAction.CreateNote.Tooltip",
image = "ui/images/note-add.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void newNote(HopGuiPipelineContext context) {
selectionRegion = null;
@@ -2804,13 +2864,53 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.PipelineAction.CopyToClipboard.Name",
tooltip =
"i18n::HopGuiPipelineGraph.PipelineAction.CopyToClipboard.Tooltip",
image = "ui/images/copy.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void copyNotePadToClipboard(HopGuiPipelineNoteContext context) {
pipelineClipboardDelegate.copySelected(
pipelineMeta, Collections.emptyList(),
Arrays.asList(context.getNotePadMeta()));
}
+ @GuiContextAction(
+ id = "pipeline-graph-30-bring-note-to-front",
+ parentId = HopGuiPipelineNoteContext.CONTEXT_ID,
+ type = GuiActionType.Modify,
+ name = "i18n::HopGuiPipelineGraph.NoteAction.BringToFront.Text",
+ tooltip = "i18n::HopGuiPipelineGraph.NoteAction.BringToFront.Tooltip",
+ image = "ui/images/bring-to-front.svg",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Arrange.Text",
+ categoryOrder = "2")
+ public void bringNoteToFront(HopGuiPipelineNoteContext context) {
+ selectionRegion = null;
+ NotePadMeta note = context.getNotePadMeta();
+ int idx = pipelineMeta.indexOfNote(note);
+ if (idx >= 0) {
+ pipelineMeta.raiseNote(idx);
+ hopGui.undoDelegate.addUndoDelete(pipelineMeta, new NotePadMeta[]
{note}, new int[] {idx});
+ }
+ redraw();
+ }
+
+ @GuiContextAction(
+ id = "pipeline-graph-40-send-note-to-back",
+ parentId = HopGuiPipelineNoteContext.CONTEXT_ID,
+ type = GuiActionType.Modify,
+ name = "i18n::HopGuiPipelineGraph.NoteAction.SendToBack.Text",
+ tooltip = "i18n::HopGuiPipelineGraph.NoteAction.SendToBack.Tooltip",
+ image = "ui/images/send-to-back.svg",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Arrange.Text",
+ categoryOrder = "2")
+ public void sendNoteToBack(HopGuiPipelineNoteContext context) {
+ selectionRegion = null;
+ NotePadMeta note = context.getNotePadMeta();
+ int idx = pipelineMeta.indexOfNote(note);
+ if (idx >= 0) {
+ pipelineMeta.lowerNote(idx);
+ hopGui.undoDelegate.addUndoDelete(pipelineMeta, new NotePadMeta[]
{note}, new int[] {idx});
+ }
+ redraw();
+ }
+
@GuiContextAction(
id = "pipeline-graph-edit-pipeline",
parentId = HopGuiPipelineContext.CONTEXT_ID,
@@ -2818,7 +2918,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.PipelineAction.EditPipeline.Name",
tooltip =
"i18n::HopGuiPipelineGraph.PipelineAction.EditPipeline.Tooltip",
image = "ui/images/pipeline.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void editPipelineProperties(HopGuiPipelineContext context) {
editProperties(pipelineMeta, hopGui, true);
@@ -3117,6 +3217,14 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
showToolTip(new org.eclipse.swt.graphics.Point(screenX, screenY));
}
+ /**
+ * Find the last area owner, the one drawn last, for the given coordinate.
In other words, this
+ * searches the provided list back-to-front.
+ *
+ * @param x The x coordinate
+ * @param y The y coordinate
+ * @return The area owner or null if nothing could be found
+ */
public synchronized AreaOwner getVisibleAreaOwner(int x, int y) {
for (int i = areaOwners.size() - 1; i >= 0; i--) {
AreaOwner areaOwner = areaOwners.get(i);
@@ -3384,8 +3492,6 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
ni.setBorderColorRed(n.getBorderColorRed());
ni.setBorderColorGreen(n.getBorderColorGreen());
ni.setBorderColorBlue(n.getBorderColorBlue());
- ni.width = ConstUi.NOTE_MIN_SIZE;
- ni.height = ConstUi.NOTE_MIN_SIZE;
NotePadMeta after = (NotePadMeta) ni.clone();
hopGui.undoDelegate.addUndoChange(
@@ -3421,7 +3527,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.HopAction.CreateHop.Name",
tooltip = "i18n::HopGuiPipelineGraph.HopAction.CreateHop.Tooltip",
image = "ui/images/hop.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void newHopCandidate(HopGuiPipelineTransformContext context) {
startHopTransform = context.getTransformMeta();
@@ -3501,7 +3607,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.PipelineAction.Preview.Name",
tooltip = "i18n::HopGuiPipelineGraph.PipelineAction.Preview.Tooltip",
image = "ui/images/preview.svg",
- category = "Preview",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Preview.Text",
categoryOrder = "3")
/** Preview a single transform */
public void preview(HopGuiPipelineTransformContext context) {
@@ -3546,7 +3652,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.PipelineAction.DebugOutput.Name",
tooltip = "i18n::HopGuiPipelineGraph.PipelineAction.DebugOutput.Tooltip",
image = "ui/images/debug.svg",
- category = "Preview",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Preview.Text",
categoryOrder = "3")
/** Debug a single transform */
public void debug(HopGuiPipelineTransformContext context) {
@@ -4704,7 +4810,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.PipelineAction.SniffOutput.Name",
tooltip = "i18n::HopGuiPipelineGraph.PipelineAction.SniffOutput.Tooltip",
image = "ui/images/preview.svg",
- category = "Preview",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Preview.Text",
categoryOrder = "3")
public void sniff(HopGuiPipelineTransformContext context) {
TransformMeta transformMeta = context.getTransformMeta();
@@ -5102,7 +5208,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name =
"i18n::HopGuiPipelineGraph.PipelineAction.PasteFromClipboard.Name",
tooltip =
"i18n::HopGuiPipelineGraph.PipelineAction.PasteFromClipboard.Tooltip",
image = "ui/images/paste.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void pasteFromClipboard(HopGuiPipelineContext context) {
pasteFromClipboard(context.getClick());
@@ -5115,7 +5221,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name = "i18n::HopGuiPipelineGraph.PipelineAction.CopyToClipboard.Name",
tooltip =
"i18n::HopGuiPipelineGraph.PipelineAction.CopyToClipboard.Tooltip",
image = "ui/images/copy.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void copyTransformToClipboard(HopGuiPipelineTransformContext context)
{
pipelineClipboardDelegate.copySelected(
@@ -5198,7 +5304,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name =
"i18n::HopGuiPipelineGraph.ContextualAction.NavigateToExecutionInfo.Text",
tooltip =
"i18n::HopGuiPipelineGraph.ContextualAction.NavigateToExecutionInfo.Tooltip",
image = "ui/images/execution.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void navigateToExecutionInfo(HopGuiPipelineContext context) {
navigateToExecutionInfo();
@@ -5305,7 +5411,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
name =
"i18n::HopGuiPipelineGraph.TransformAction.ViewExecutionInfo.Name",
tooltip =
"i18n::HopGuiPipelineGraph.TransformAction.ViewExecutionInfo.Tooltip",
image = "ui/images/execution.svg",
- category = "Basic",
+ category =
"i18n::HopGuiPipelineGraph.ContextualAction.Category.Basic.Text",
categoryOrder = "1")
public void viewTransformExecutionInfo(HopGuiPipelineTransformContext
context) {
try {
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/HopGuiAbstractGraph.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/HopGuiAbstractGraph.java
index a64941ec9b..d633a5ad9f 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/HopGuiAbstractGraph.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/HopGuiAbstractGraph.java
@@ -20,6 +20,8 @@ package org.apache.hop.ui.hopgui.file.shared;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
+import lombok.Getter;
+import org.apache.hop.core.NotePadMeta;
import org.apache.hop.core.gui.DPoint;
import org.apache.hop.core.gui.Point;
import org.apache.hop.core.gui.Rectangle;
@@ -29,14 +31,13 @@ import
org.apache.hop.core.gui.plugin.key.GuiOsxKeyboardShortcut;
import org.apache.hop.core.variables.IVariables;
import org.apache.hop.core.variables.Variables;
import org.apache.hop.ui.core.ConstUi;
+import org.apache.hop.ui.core.PropsUi;
import org.apache.hop.ui.core.gui.GuiMenuWidgets;
-import org.apache.hop.ui.core.gui.GuiResource;
import org.apache.hop.ui.hopgui.HopGui;
import org.apache.hop.ui.hopgui.file.IGraphSnapAlignDistribute;
import org.apache.hop.ui.hopgui.file.IHopFileType;
import org.apache.hop.ui.hopgui.perspective.execution.DragViewZoomBase;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
@@ -52,25 +53,20 @@ public abstract class HopGuiAbstractGraph extends
DragViewZoomBase
public static final String STATE_MAGNIFICATION = "magnification";
public static final String STATE_SCROLL_X_SELECTION = "offset-x";
public static final String STATE_SCROLL_Y_SELECTION = "offset-y";
+ protected final String id;
protected HopGui hopGui;
-
protected IVariables variables;
-
protected Composite parentComposite;
-
protected Point iconOffset;
protected Point noteOffset;
-
- private boolean changedState;
- private final Font defaultFont;
-
- protected final String id;
-
+ protected Rectangle resizeArea;
+ protected Resize resize;
protected ToolTip toolTip;
-
protected String mouseOverName;
+ private boolean changedState;
+
/**
* This is a state map which can be used by plugins to render extra states
on top of pipelines and
* workflows or their components.
@@ -83,7 +79,6 @@ public abstract class HopGuiAbstractGraph extends
DragViewZoomBase
this.hopGui = hopGui;
this.variables = new Variables();
this.variables.copyFrom(hopGui.getVariables());
- this.defaultFont = GuiResource.getInstance().getFontDefault();
this.changedState = false;
this.id = UUID.randomUUID().toString();
this.stateMap = new HashMap<>();
@@ -203,6 +198,162 @@ public abstract class HopGuiAbstractGraph extends
DragViewZoomBase
setChanged();
}
+ /**
+ * Evaluates whether the point is near any of the edges or corners of the
rectangle and returns
+ * the corresponding resize direction.
+ *
+ * @param rectangle the rectangle to check against
+ * @param point the point whose position is evaluated
+ * @return the resize direction as {@link Resize} enum; returns null if the
point does not
+ * correspond with any resize region
+ */
+ public Resize getResize(Rectangle rectangle, Point point) {
+ // West border
+ if (point.x <= rectangle.x + 4) {
+ if (point.y <= rectangle.y + 4) return Resize.NORTH_WEST;
+ if (point.y >= rectangle.y + rectangle.height - 4) return
Resize.SOUTH_WEST;
+ return Resize.WEST;
+ }
+
+ // East border
+ if (point.x >= rectangle.x + rectangle.width - 4) {
+ if (point.y <= rectangle.y + 4) return Resize.NORTH_EAST;
+ if (point.y >= rectangle.y + rectangle.height - 4) return
Resize.SOUTH_EAST;
+ return Resize.EAST;
+ }
+
+ // North
+ if (point.y <= rectangle.y + 4) {
+ return Resize.NORTH;
+ }
+ if (point.y >= rectangle.y + rectangle.height - 4) {
+ return Resize.SOUTH;
+ }
+ return null;
+ }
+
+ /**
+ * Resizes the given {@link NotePadMeta} based on the original area, the
specified resize
+ * direction and real mouse position.
+ *
+ * @param noteMeta the metadata of the note to be resized
+ * @param real the current position of the mouse used for calculating the
resize dimensions
+ */
+ protected void resizeNote(NotePadMeta noteMeta, Point real) {
+ switch (resize) {
+ case EAST -> {
+ int width = real.x - resizeArea.x;
+ if (width < noteMeta.getMinimumWidth()) {
+ width = noteMeta.getMinimumWidth();
+ }
+ PropsUi.setSize(noteMeta, width, resizeArea.height);
+ }
+ case NORTH -> {
+ int y = real.y;
+ if (y < 0) {
+ y = 0;
+ }
+ if (y > resizeArea.y + resizeArea.height -
noteMeta.getMinimumHeight()) {
+ y = resizeArea.y + resizeArea.height - noteMeta.getMinimumHeight();
+ }
+ PropsUi.setLocation(noteMeta, resizeArea.x, y);
+ PropsUi.setSize(
+ noteMeta,
+ resizeArea.width,
+ resizeArea.y + resizeArea.height - noteMeta.getLocation().y);
+ }
+ case NORTH_EAST -> {
+ int x = real.x;
+ if (x < 0) {
+ x = 0;
+ }
+ int width = real.x - resizeArea.x;
+ if (width < noteMeta.getMinimumWidth()) {
+ width = noteMeta.getMinimumWidth();
+ }
+ int y = real.y;
+ if (y < 0) {
+ y = 0;
+ }
+ if (y > resizeArea.y + resizeArea.height -
noteMeta.getMinimumHeight()) {
+ y = resizeArea.y + resizeArea.height - noteMeta.getMinimumHeight();
+ }
+ PropsUi.setLocation(noteMeta, resizeArea.x, y);
+ PropsUi.setSize(
+ noteMeta, width, resizeArea.y + resizeArea.height -
noteMeta.getLocation().y);
+ }
+ case NORTH_WEST -> {
+ int x = real.x;
+ if (x < 0) {
+ x = 0;
+ }
+ if (x > resizeArea.x + resizeArea.width - noteMeta.getMinimumWidth()) {
+ x = resizeArea.x + resizeArea.width - noteMeta.getMinimumWidth();
+ }
+ int y = real.y;
+ if (y < 0) {
+ y = 0;
+ }
+ if (y > resizeArea.y + resizeArea.height -
noteMeta.getMinimumHeight()) {
+ y = resizeArea.y + resizeArea.height - noteMeta.getMinimumHeight();
+ }
+ PropsUi.setLocation(noteMeta, x, y);
+ PropsUi.setSize(
+ noteMeta,
+ resizeArea.x + resizeArea.width - noteMeta.getLocation().x,
+ resizeArea.height + resizeArea.y - noteMeta.getLocation().y);
+ }
+ case SOUTH -> {
+ int height = real.y - resizeArea.y;
+ if (height < noteMeta.getMinimumHeight()) {
+ height = noteMeta.getMinimumHeight();
+ }
+ PropsUi.setSize(noteMeta, resizeArea.width, height);
+ }
+ case SOUTH_EAST -> {
+ int width = real.x - resizeArea.x;
+ if (width < noteMeta.getMinimumWidth()) {
+ width = noteMeta.getMinimumWidth();
+ }
+ int height = real.y - resizeArea.y;
+ if (height < noteMeta.getMinimumHeight()) {
+ height = noteMeta.getMinimumHeight();
+ }
+ PropsUi.setSize(noteMeta, width, height);
+ }
+ case SOUTH_WEST -> {
+ int x = real.x;
+ if (x < 0) {
+ x = 0;
+ }
+ if (x > resizeArea.x + resizeArea.width - noteMeta.getMinimumWidth()) {
+ x = resizeArea.x + resizeArea.width - noteMeta.getMinimumWidth();
+ }
+ int height = real.y - resizeArea.y;
+ if (height < noteMeta.getMinimumHeight()) {
+ height = noteMeta.getMinimumHeight();
+ }
+ PropsUi.setLocation(noteMeta, x, resizeArea.y);
+ PropsUi.setSize(
+ noteMeta, resizeArea.x + resizeArea.width -
noteMeta.getLocation().x, height);
+ }
+ case WEST -> {
+ int x = real.x;
+ if (x < 0) {
+ x = 0;
+ }
+ if (x > resizeArea.x + resizeArea.width - noteMeta.getMinimumWidth()) {
+ x = resizeArea.x + resizeArea.width - noteMeta.getMinimumWidth();
+ }
+ PropsUi.setLocation(noteMeta, x, resizeArea.y);
+ PropsUi.setSize(
+ noteMeta,
+ resizeArea.x + resizeArea.width - noteMeta.getLocation().x,
+ resizeArea.height);
+ }
+ }
+ }
+
/**
* Gets variables
*
@@ -346,4 +497,21 @@ public abstract class HopGuiAbstractGraph extends
DragViewZoomBase
public void setMouseOverName(String mouseOverName) {
this.mouseOverName = mouseOverName;
}
+
+ public enum Resize {
+ EAST(SWT.CURSOR_SIZEW),
+ NORTH(SWT.CURSOR_SIZENS),
+ NORTH_EAST(SWT.CURSOR_SIZENESW),
+ NORTH_WEST(SWT.CURSOR_SIZENW),
+ SOUTH(SWT.CURSOR_SIZENS),
+ SOUTH_EAST(SWT.CURSOR_SIZENW),
+ SOUTH_WEST(SWT.CURSOR_SIZENESW),
+ WEST(SWT.CURSOR_SIZEW);
+
+ @Getter private final int cursor;
+
+ Resize(int cursor) {
+ this.cursor = cursor;
+ }
+ }
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopGuiWorkflowGraph.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopGuiWorkflowGraph.java
index e7b9714011..c121fbe9da 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopGuiWorkflowGraph.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopGuiWorkflowGraph.java
@@ -342,7 +342,7 @@ public class HopGuiWorkflowGraph extends HopGuiAbstractGraph
private ActionMeta endHopAction;
private ActionMeta noInputAction;
- private Point[] previousTransformLocations;
+ private Point[] previousActionLocations;
private Point[] previousNoteLocations;
private ActionMeta currentAction;
private boolean ignoreNextClick;
@@ -544,6 +544,7 @@ public class HopGuiWorkflowGraph extends HopGuiAbstractGraph
mouseHover(event);
}
doubleClick = false;
+ resize = null;
if (ignoreNextClick) {
ignoreNextClick = false;
@@ -553,9 +554,9 @@ public class HopGuiWorkflowGraph extends HopGuiAbstractGraph
boolean control = (event.stateMask & SWT.MOD1) != 0;
boolean shift = (event.stateMask & SWT.SHIFT) != 0;
- lastButton = event.button;
Point real = screen2real(event.x, event.y);
lastClick = new Point(real.x, real.y);
+ lastButton = event.button;
// Hide the tooltip!
hideToolTips();
@@ -574,142 +575,180 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
LogChannel.GENERAL.logError("Error calling WorkflowGraphMouseDown
extension point", ex);
}
- // A single left or middle click on one of the area owners...
+ // Layer 0: See if we're dragging around the view-port over the workflow
graph.
//
- if (event.button == 1 || event.button == 2) {
- if (areaOwner != null && areaOwner.getAreaType() != null) {
- switch (areaOwner.getAreaType()) {
- case ACTION_ICON:
- if (shift && control) {
- openReferencedObject();
- return;
- }
-
- ActionMeta actionCopy = (ActionMeta) areaOwner.getOwner();
- currentAction = actionCopy;
+ Point clickScreen = new Point(event.x, event.y);
+ if (setupDragViewPort(clickScreen)) {
+ return;
+ }
- if (hopCandidate != null) {
- addCandidateAsHop();
+ // A single left or middle click on one of the area owners...
+ //
+ boolean done = false;
- } else if (event.button == 2 || (event.button == 1 && shift)) {
- // SHIFT CLICK is start of drag to create a new hop
- //
- canvas.setData("mode", "hop");
- startHopAction = actionCopy;
+ // Layer 1: Click on an area owner except note (else if a note is present
in the background,
+ // you cannot click the hop link).
+ if (areaOwner != null && areaOwner.getAreaType() != null) {
+ switch (areaOwner.getAreaType()) {
+ case ACTION_ICON:
+ if (shift && control) {
+ openReferencedObject();
+ return;
+ }
- } else {
- canvas.setData("mode", "drag");
- selectedActions = workflowMeta.getSelectedActions();
- selectedAction = actionCopy;
- //
- // When an icon is moved that is not selected, it gets
- // selected too late.
- // It is not captured here, but in the mouseMoveListener...
- //
- previousTransformLocations = workflowMeta.getSelectedLocations();
+ ActionMeta actionCopy = (ActionMeta) areaOwner.getOwner();
+ currentAction = actionCopy;
- Point p = actionCopy.getLocation();
- iconOffset = new Point(real.x - p.x, real.y - p.y);
- }
- updateGui();
- break;
+ if (hopCandidate != null) {
+ addCandidateAsHop();
- case ACTION_INFO_ICON:
- // Click on the info icon means: Edit action description
+ } else if (event.button == 2 || (event.button == 1 && shift)) {
+ // SHIFT CLICK is start of drag to create a new hop
//
- editActionDescription((ActionMeta) areaOwner.getOwner());
- break;
-
- case NOTE:
- currentNotePad = (NotePadMeta) areaOwner.getOwner();
- selectedNotes = workflowMeta.getSelectedNotes();
- selectedNote = currentNotePad;
- Point loc = currentNotePad.getLocation();
+ canvas.setData("mode", "hop");
+ startHopAction = actionCopy;
+ } else {
+ canvas.setData("mode", "drag");
+ selectedActions = workflowMeta.getSelectedActions();
+ selectedAction = actionCopy;
+ //
+ // When an icon is moved that is not selected, it gets
+ // selected too late.
+ // It is not captured here, but in the mouseMoveListener...
+ //
+ previousActionLocations = workflowMeta.getSelectedLocations();
- previousNoteLocations = workflowMeta.getSelectedNoteLocations();
+ Point p = actionCopy.getLocation();
+ iconOffset = new Point(real.x - p.x, real.y - p.y);
+ }
+ updateGui();
+ done = true;
+ break;
- noteOffset = new Point(real.x - loc.x, real.y - loc.y);
+ case ACTION_NAME:
+ done = true;
+ break;
- updateGui();
- break;
+ case ACTION_INFO_ICON:
+ // Click on the info icon means: Edit action description
+ //
+ editActionDescription((ActionMeta) areaOwner.getOwner());
+ done = true;
+ break;
- // If you click on an evaluating icon, change the evaluation...
- //
- case WORKFLOW_HOP_ICON:
- WorkflowHopMeta hop = (WorkflowHopMeta) areaOwner.getOwner();
- WorkflowHopMeta originalHop = hop.clone();
- if (hop.getFromAction().isEvaluation()) {
- if (hop.isUnconditional()) {
- hop.setUnconditional(false);
- hop.setEvaluation(true);
+ // If you click on an evaluating icon, change the evaluation...
+ //
+ case WORKFLOW_HOP_ICON:
+ WorkflowHopMeta hop = (WorkflowHopMeta) areaOwner.getOwner();
+ WorkflowHopMeta originalHop = hop.clone();
+ if (hop.getFromAction().isEvaluation()) {
+ if (hop.isUnconditional()) {
+ hop.setUnconditional(false);
+ hop.setEvaluation(true);
+ } else {
+ if (hop.isEvaluation()) {
+ hop.setEvaluation(false);
} else {
- if (hop.isEvaluation()) {
- hop.setEvaluation(false);
- } else {
- hop.setUnconditional(true);
- }
+ hop.setUnconditional(true);
}
- hopGui.undoDelegate.addUndoChange(
- workflowMeta,
- new WorkflowHopMeta[] {originalHop},
- new WorkflowHopMeta[] {hop},
- new int[] {workflowMeta.indexOfWorkflowHop(hop)});
- updateGui();
}
- break;
- default:
- break;
- }
- } else {
- WorkflowHopMeta hop = findWorkflowHop(real.x, real.y);
- if (hop != null) {
- // Delete hop with on click
- if (event.button == 1 && shift && control) {
- // Delete the hop
- workflowHopDelegate.delHop(workflowMeta, hop);
- updateGui();
- }
- // User held control and clicked a hop between actions - We want to
flip the active state
- // of
- // the hop.
- //
- else if (event.button == 2 || (event.button == 1 && control)) {
- hop.setEnabled(!hop.isEnabled());
+ hopGui.undoDelegate.addUndoChange(
+ workflowMeta,
+ new WorkflowHopMeta[] {originalHop},
+ new WorkflowHopMeta[] {hop},
+ new int[] {workflowMeta.indexOfWorkflowHop(hop)});
updateGui();
- } else {
- // A hop: show the hop context menu in the mouseUp() listener
- //
- clickedWorkflowHop = hop;
}
+ done = true;
+ break;
+ case NOTE:
+ default:
+ break;
+ }
+ }
+
+ // Layer 2: click on hop links between actions
+ if (!done) {
+ // Hop links between actions are found searching by (x,y) coordinates.
+ WorkflowHopMeta hop = findWorkflowHop(real.x, real.y);
+ if (hop != null) {
+ // Delete hop with on click
+ if (event.button == 1 && shift && control) {
+ // Delete the hop
+ workflowHopDelegate.delHop(workflowMeta, hop);
+ updateGui();
+ }
+ // User held control and clicked a hop between actions - We want to
flip the active state
+ // of
+ // the hop.
+ //
+ else if (event.button == 2 || (event.button == 1 && control)) {
+ hop.setEnabled(!hop.isEnabled());
+ updateGui();
} else {
- // If we're dragging a candidate hop around and click on the
background it simply needs to
- // go away.
+ // A hop: show the hop context menu in the mouseUp() listener
//
- if (startHopAction != null) {
- startHopAction = null;
- hopCandidate = null;
- lastClick = null;
- redraw();
- return;
- }
+ clickedWorkflowHop = hop;
+ }
+ done = true;
+ }
+ }
- // Dragging on the background?
- // See if we're dragging around the view-port over the workflow
graph.
- //
- if (setupDragView(event.button, control, new Point(event.x,
event.y))) {
- return;
- }
+ // Layer 3: click on a note
+ if (!done && areaOwner != null && areaOwner.getAreaType() ==
AreaOwner.AreaType.NOTE) {
+ currentNotePad = (NotePadMeta) areaOwner.getOwner();
+ selectedNotes = workflowMeta.getSelectedNotes();
+ selectedNote = currentNotePad;
+ Point loc = currentNotePad.getLocation();
- // No area-owner means: background:
- //
- canvas.setData("mode", "select");
- if (!control && event.button == 1) {
- selectionRegion = new org.apache.hop.core.gui.Rectangle(real.x,
real.y, 0, 0);
- }
- updateGui();
- }
+ previousNoteLocations = workflowMeta.getSelectedNoteLocations();
+
+ noteOffset = new Point(real.x - loc.x, real.y - loc.y);
+
+ canvas.setData("mode", "resize");
+ resize = this.getResize(areaOwner.getArea(), real);
+ // Keep the original area of the resizing note
+ resizeArea =
+ new Rectangle(
+ currentNotePad.getLocation().x,
+ currentNotePad.getLocation().y,
+ currentNotePad.getWidth(),
+ currentNotePad.getHeight());
+
+ updateGui();
+ done = true;
+ }
+
+ // Layer 4: Click on the background of the graph
+ if (!done) {
+
+ // If we're dragging a candidate hop around and click on the background
it simply needs to
+ // go away.
+ //
+ if (startHopAction != null) {
+ startHopAction = null;
+ hopCandidate = null;
+ lastClick = null;
+ redraw();
+ return;
+ }
+
+ // Click to drag the background
+ if (setupDragView(event.button, control, clickScreen)) {
+ return;
+ }
+
+ // Click to create a lasso
+ //
+ canvas.setData("mode", "select");
+ if (!control && event.button == 1) {
+ selectionRegion = new org.apache.hop.core.gui.Rectangle(real.x,
real.y, 0, 0);
+ // Change cursor when selecting a region
+ setCursor(getDisplay().getSystemCursor(SWT.CURSOR_CROSS));
}
+ updateGui();
}
+
if (EnvironmentUtils.getInstance().isWeb()) {
// RAP does not support certain mouse events.
mouseMove(event);
@@ -726,6 +765,8 @@ public class HopGuiWorkflowGraph extends HopGuiAbstractGraph
@Override
public void mouseUp(MouseEvent event) {
+ resize = null;
+
// canvas.setData("mode", null); does not work.
canvas.setData("mode", "null");
if (EnvironmentUtils.getInstance().isWeb()) {
@@ -866,12 +907,12 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
}
if (selectedActions != null
&& !selectedActions.isEmpty()
- && previousTransformLocations != null) {
+ && previousActionLocations != null) {
int[] indexes = workflowMeta.getActionIndexes(selectedActions);
addUndoPosition(
selectedActions.toArray(new
ActionMeta[selectedActions.size()]),
indexes,
- previousTransformLocations,
+ previousActionLocations,
workflowMeta.getSelectedLocations(),
also);
}
@@ -934,6 +975,13 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
singleClick = true;
singleClickType = SingleClickType.Note;
singleClickNote = selectedNote;
+
+ // If the clicked note is not part of the current selection,
cancel the
+ // current selection
+ if (!selectedNote.isSelected()) {
+ workflowMeta.unselectAll();
+ selectedNote.setSelected(true);
+ }
}
} else {
// Find out which Transforms & Notes are selected
@@ -956,12 +1004,12 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
}
if (selectedActions != null
&& !selectedActions.isEmpty()
- && previousTransformLocations != null) {
+ && previousActionLocations != null) {
int[] indexes = workflowMeta.getActionIndexes(selectedActions);
addUndoPosition(
selectedActions.toArray(new
ActionMeta[selectedActions.size()]),
indexes,
- previousTransformLocations,
+ previousActionLocations,
workflowMeta.getSelectedLocations(),
also);
}
@@ -1115,7 +1163,6 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
boolean shift = (event.stateMask & SWT.SHIFT) != 0;
noInputAction = null;
boolean doRedraw = false;
- WorkflowHopMeta hop = null;
// disable the tooltip
//
@@ -1129,6 +1176,7 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
}
Point real = screen2real(event.x, event.y);
+
// Remember the last position of the mouse for paste with keyboard
//
lastMove = real;
@@ -1143,29 +1191,53 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
}
Point note = new Point(real.x - noteOffset.x, real.y - noteOffset.y);
+ // First, check for operations that have been started, such as move
selection, dragging the
+ // view, creating a hop or
+ // resizing a note.
+
+ // Drag the view around with middle button on the background?
+ //
+ if (viewDrag && lastClick != null) {
+ dragView(viewDragStart, new Point(event.x, event.y));
+ return;
+ }
+
+ // Resizing the current note
+ if (resize != null) {
+ resizeNote(selectedNote, real);
+ redraw();
+ return;
+ }
+
// Moved over an area?
//
AreaOwner areaOwner = getVisibleAreaOwner(real.x, real.y);
+ Resize resizeOver = null;
// Moved over an hop?
//
- if (areaOwner == null) {
- hop = findWorkflowHop(real.x, real.y);
- }
+ if (areaOwner != null) {
- // Mouse over the name of the action
- //
- if (!PropsUi.getInstance().useDoubleClick()) {
- if (areaOwner != null && areaOwner.getAreaType() ==
AreaOwner.AreaType.ACTION_NAME) {
- if (mouseOverName == null) {
- doRedraw = true;
- }
- mouseOverName = (String) areaOwner.getOwner();
- } else {
- if (mouseOverName != null) {
- doRedraw = true;
+ // Mouse over the name of the action
+ //
+ if (!PropsUi.getInstance().useDoubleClick()) {
+ if (areaOwner != null && areaOwner.getAreaType() ==
AreaOwner.AreaType.ACTION_NAME) {
+ if (mouseOverName == null) {
+ doRedraw = true;
+ }
+ mouseOverName = (String) areaOwner.getOwner();
+ } else {
+ if (mouseOverName != null) {
+ doRedraw = true;
+ }
+ mouseOverName = null;
}
- mouseOverName = null;
+ }
+
+ // Mouse over note
+ if (areaOwner.getAreaType() == AreaOwner.AreaType.NOTE) {
+ // Check if the mouse is over the border to activate a resize cursor
+ resizeOver = this.getResize(areaOwner.getArea(), real);
}
}
@@ -1179,7 +1251,7 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
selectedAction.setSelected(true);
selectedActions = new ArrayList<>();
selectedActions.add(selectedAction);
- previousTransformLocations = new Point[] {selectedAction.getLocation()};
+ previousActionLocations = new Point[] {selectedAction.getLocation()};
doRedraw = true;
} else if (selectedNote != null && !selectedNote.isSelected()) {
workflowMeta.unselectAll();
@@ -1269,12 +1341,6 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
}
doRedraw = true;
- } else {
- // Drag the view around with middle button on the background?
- //
- if (viewDrag && lastClick != null) {
- dragView(viewDragStart, new Point(event.x, event.y));
- }
}
// Move around notes & actions
@@ -1295,18 +1361,22 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
Cursor cursor = null;
// Change cursor when dragging view or view port
- if (viewDrag || viewPortNavigation) {
- cursor = getDisplay().getSystemCursor(SWT.CURSOR_SIZEALL);
- }
+ // if (viewDrag || viewPortNavigation) {
+ // cursor = getDisplay().getSystemCursor(SWT.CURSOR_SIZEALL);
+ // }
// Change cursor when selecting a region
- else if (selectionRegion != null) {
- cursor = getDisplay().getSystemCursor(SWT.CURSOR_CROSS);
- }
- // Change cursor when hover an hop or an area that support hover
- else if (hop != null
- || (areaOwner != null
+ // else if (selectionRegion != null) {
+ // cursor = getDisplay().getSystemCursor(SWT.CURSOR_CROSS);
+ /// } else
+ // Change the cursor when the mouse is on the resize edge of a note
+ if (resizeOver != null) {
+ cursor = getDisplay().getSystemCursor(resizeOver.getCursor());
+ }
+ // Change cursor when the mouse is on a hop or an area that support
hovering
+ else if ((areaOwner != null
&& areaOwner.getAreaType() != null
- && areaOwner.getAreaType().isSupportHover())) {
+ && areaOwner.getAreaType().isSupportHover())
+ || findWorkflowHop(real.x, real.y) != null) {
cursor = getDisplay().getSystemCursor(SWT.CURSOR_HAND);
}
setCursor(cursor);
@@ -1402,7 +1472,15 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
return ok;
}
- public AreaOwner getVisibleAreaOwner(int x, int y) {
+ /**
+ * Find the last area owner, the one drawn last, for the given coordinate.
In other words, this
+ * searches the provided list back-to-front.
+ *
+ * @param x The x coordinate
+ * @param y The y coordinate
+ * @return The area owner or null if nothing could be found
+ */
+ public synchronized AreaOwner getVisibleAreaOwner(int x, int y) {
for (int i = areaOwners.size() - 1; i >= 0; i--) {
AreaOwner areaOwner = areaOwners.get(i);
if (areaOwner.contains(x, y)) {
@@ -1729,24 +1807,24 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
}
/**
- * See if location (x,y) is on a line between two transforms: the hop!
+ * See if the location (x,y) is on a line between two actions: the hop!
*
* @param x
* @param y
- * @return the pipeline hop on the specified location, otherwise: null
+ * @return the workflow hop on the specified location, otherwise: null
*/
private WorkflowHopMeta findWorkflowHop(int x, int y) {
return findHop(x, y, null);
}
/**
- * See if location (x,y) is on a line between two transforms: the hop!
+ * See if the location (x,y) is on a line between two actions: the hop!
*
* @param x
* @param y
- * @param exclude the transform to exclude from the hops (from or to
location). Specify null if no
- * transform is to be excluded.
- * @return the pipeline hop on the specified location, otherwise: null
+ * @param exclude the action to exclude from the hops (from or to location).
Specify null if no
+ * action is to be excluded.
+ * @return the workflow hop on the specified location, otherwise: null
*/
private WorkflowHopMeta findHop(int x, int y, ActionMeta exclude) {
int i;
@@ -2070,32 +2148,32 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
categoryOrder = "1")
public void newNote(HopGuiWorkflowContext context) {
String title = BaseMessages.getString(PKG,
"WorkflowGraph.Dialog.EditNote.Title");
- NotePadDialog dd = new NotePadDialog(variables, hopShell(), title);
- NotePadMeta n = dd.open();
- if (n != null) {
- NotePadMeta npi =
+ NotePadDialog dialog = new NotePadDialog(variables, hopShell(), title);
+ NotePadMeta note = dialog.open();
+ if (note != null) {
+ NotePadMeta newNote =
new NotePadMeta(
- n.getNote(),
+ note.getNote(),
context.getClick().x,
context.getClick().y,
ConstUi.NOTE_MIN_SIZE,
ConstUi.NOTE_MIN_SIZE,
- n.getFontName(),
- n.getFontSize(),
- n.isFontBold(),
- n.isFontItalic(),
- n.getFontColorRed(),
- n.getFontColorGreen(),
- n.getFontColorBlue(),
- n.getBackGroundColorRed(),
- n.getBackGroundColorGreen(),
- n.getBackGroundColorBlue(),
- n.getBorderColorRed(),
- n.getBorderColorGreen(),
- n.getBorderColorBlue());
- workflowMeta.addNote(npi);
+ note.getFontName(),
+ note.getFontSize(),
+ note.isFontBold(),
+ note.isFontItalic(),
+ note.getFontColorRed(),
+ note.getFontColorGreen(),
+ note.getFontColorBlue(),
+ note.getBackGroundColorRed(),
+ note.getBackGroundColorGreen(),
+ note.getBackGroundColorBlue(),
+ note.getBorderColorRed(),
+ note.getBorderColorGreen(),
+ note.getBorderColorBlue());
+ workflowMeta.addNote(newNote);
hopGui.undoDelegate.addUndoNew(
- workflowMeta, new NotePadMeta[] {npi}, new int[]
{workflowMeta.indexOfNote(npi)});
+ workflowMeta, new NotePadMeta[] {newNote}, new int[]
{workflowMeta.indexOfNote(newNote)});
redraw();
}
}
@@ -2142,20 +2220,42 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
redraw();
}
- public void raiseNote() {
+ @GuiContextAction(
+ id = "workflow-graph-30-bring-note-to-front",
+ parentId = HopGuiWorkflowNoteContext.CONTEXT_ID,
+ type = GuiActionType.Modify,
+ name =
"i18n::HopGuiWorkflowGraph.ContextualAction.BringNoteToFront.Text",
+ tooltip =
"i18n::HopGuiWorkflowGraph.ContextualAction.BringNoteToFront.Tooltip",
+ image = "ui/images/bring-to-front.svg",
+ category =
"i18n::HopGuiWorkflowGraph.ContextualAction.Category.Arrange.Text",
+ categoryOrder = "2")
+ public void bringNoteToFront(HopGuiWorkflowNoteContext context) {
selectionRegion = null;
- int idx = workflowMeta.indexOfNote(getCurrentNote());
+ NotePadMeta note = context.getNotePadMeta();
+ int idx = workflowMeta.indexOfNote(note);
if (idx >= 0) {
workflowMeta.raiseNote(idx);
+ hopGui.undoDelegate.addUndoDelete(workflowMeta, new NotePadMeta[]
{note}, new int[] {idx});
}
redraw();
}
- public void lowerNote() {
+ @GuiContextAction(
+ id = "workflow-graph-40-send-note-to-back",
+ parentId = HopGuiWorkflowNoteContext.CONTEXT_ID,
+ type = GuiActionType.Modify,
+ name = "i18n::HopGuiWorkflowGraph.ContextualAction.SendNoteToBack.Text",
+ tooltip =
"i18n::HopGuiWorkflowGraph.ContextualAction.SendNoteToBack.Tooltip",
+ image = "ui/images/send-to-back.svg",
+ category =
"i18n::HopGuiWorkflowGraph.ContextualAction.Category.Arrange.Text",
+ categoryOrder = "2")
+ public void sendNoteToBack(HopGuiWorkflowNoteContext context) {
selectionRegion = null;
- int idx = workflowMeta.indexOfNote(getCurrentNote());
+ NotePadMeta note = context.getNotePadMeta();
+ int idx = workflowMeta.indexOfNote(note);
if (idx >= 0) {
workflowMeta.lowerNote(idx);
+ hopGui.undoDelegate.addUndoDelete(workflowMeta, new NotePadMeta[]
{note}, new int[] {idx});
}
redraw();
}
@@ -3045,8 +3145,8 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
new NotePadMeta[] {before},
new NotePadMeta[] {notePadMeta},
new int[] {workflowMeta.indexOfNote(notePadMeta)});
- notePadMeta.width = ConstUi.NOTE_MIN_SIZE;
- notePadMeta.height = ConstUi.NOTE_MIN_SIZE;
+ // notePadMeta.width = ConstUi.NOTE_MIN_SIZE;
+ // notePadMeta.height = ConstUi.NOTE_MIN_SIZE;
updateGui();
}
@@ -4207,7 +4307,7 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
new ErrorDialog(
getShell(),
CONST_ERROR,
- "Error navigating to the latest execution information for this
pipeline",
+ "Error navigating to the latest execution information for this
workflow",
e);
}
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/DragViewZoomBase.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/DragViewZoomBase.java
index bc34371cc6..61b7f5463f 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/DragViewZoomBase.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/DragViewZoomBase.java
@@ -257,17 +257,6 @@ public abstract class DragViewZoomBase extends Composite {
* @return
*/
protected boolean setupDragView(int button, boolean control, Point
screenClick) {
- // See if this is a click on the navigation view inner rectangle with the
goal of dragging it
- // around a bit.
- //
- if (viewPort != null && viewPort.contains(screenClick)) {
- viewPortNavigation = true;
- viewPortStart = new Point(screenClick);
- viewDragBaseOffset = new DPoint(offset);
- setCursor(getDisplay().getSystemCursor(SWT.CURSOR_SIZEALL));
- return true;
- }
-
// Middle button
// CTRL + left button
//
@@ -275,6 +264,23 @@ public abstract class DragViewZoomBase extends Composite {
if (viewDrag) {
viewDragStart = screenClick;
viewDragBaseOffset = new DPoint(offset);
+ // Change cursor when dragging view
+ setCursor(getDisplay().getSystemCursor(SWT.CURSOR_SIZEALL));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * See if this is a click on the navigation view inner rectangle with the
goal of dragging it
+ * around a bit.
+ */
+ protected boolean setupDragViewPort(Point screenClick) {
+ if (viewPort != null && viewPort.contains(screenClick)) {
+ viewPortNavigation = true;
+ viewPortStart = new Point(screenClick);
+ viewDragBaseOffset = new DPoint(offset);
+ // Change cursor when dragging view port
setCursor(getDisplay().getSystemCursor(SWT.CURSOR_SIZEALL));
return true;
}
diff --git
a/ui/src/main/resources/org/apache/hop/ui/hopgui/file/pipeline/messages/messages_en_US.properties
b/ui/src/main/resources/org/apache/hop/ui/hopgui/file/pipeline/messages/messages_en_US.properties
index 2d68245bf6..1078da9da0 100644
---
a/ui/src/main/resources/org/apache/hop/ui/hopgui/file/pipeline/messages/messages_en_US.properties
+++
b/ui/src/main/resources/org/apache/hop/ui/hopgui/file/pipeline/messages/messages_en_US.properties
@@ -15,6 +15,11 @@
# limitations under the License.
#
+HopGuiPipelineGraph.ContextualAction.Category.Arrange.Text=Arrange
+HopGuiPipelineGraph.ContextualAction.Category.Basic.Text=Basic
+HopGuiPipelineGraph.ContextualAction.Category.Bulk.Text=Bulk
+HopGuiPipelineGraph.ContextualAction.Category.Preview.Text=Preview
+HopGuiPipelineGraph.ContextualAction.Category.Routing.Text=Data routing
HopGuiPipelineGraph.ContextualAction.NavigateToExecutionInfo.Text=To execution
info
HopGuiPipelineGraph.ContextualAction.NavigateToExecutionInfo.Tooltip=Navigate
to the execution information for this pipeline
HopGuiPipelineGraph.DistributionMethodDialog.Header=Select distribution method
@@ -42,12 +47,16 @@ HopGuiPipelineGraph.HopAction.EnableHop.Name=Enable hop
HopGuiPipelineGraph.HopAction.EnableHop.Tooltip=Enable the hop
HopGuiPipelineGraph.HopAction.InsetTransform.Text=Insert transform
HopGuiPipelineGraph.HopAction.InsetTransform.Tooltip=Split the hop and insert
a new transform
+HopGuiPipelineGraph.NoteAction.BringToFront.Text=Bring to front
+HopGuiPipelineGraph.NoteAction.BringToFront.Tooltip=Bring note to front
HopGuiPipelineGraph.NoteAction.CreateNote.Name=Create a note
HopGuiPipelineGraph.NoteAction.CreateNote.Tooltip=Create a new note
HopGuiPipelineGraph.NoteAction.DeleteNote.Name=Delete
HopGuiPipelineGraph.NoteAction.DeleteNote.Tooltip=Delete the note
HopGuiPipelineGraph.NoteAction.EditNote.Name=Edit
HopGuiPipelineGraph.NoteAction.EditNote.Tooltip=Edit the note
+HopGuiPipelineGraph.NoteAction.SendToBack.Text=Send to back
+HopGuiPipelineGraph.NoteAction.SendToBack.Tooltip=Send note to back
HopGuiPipelineGraph.PipelineAction.CopyToClipboard.Name=Copy to clipboard
HopGuiPipelineGraph.PipelineAction.CopyToClipboard.Tooltip=Copy the XML
representation of this object to the clipboard
HopGuiPipelineGraph.PipelineAction.DebugOutput.Name=Debug output
diff --git
a/ui/src/main/resources/org/apache/hop/ui/hopgui/file/workflow/messages/messages_en_US.properties
b/ui/src/main/resources/org/apache/hop/ui/hopgui/file/workflow/messages/messages_en_US.properties
index 4b12332932..220e466963 100644
---
a/ui/src/main/resources/org/apache/hop/ui/hopgui/file/workflow/messages/messages_en_US.properties
+++
b/ui/src/main/resources/org/apache/hop/ui/hopgui/file/workflow/messages/messages_en_US.properties
@@ -18,10 +18,13 @@
HopGuiWorkflowGraph.ActionAction.ViewExecutionInfo.Name=View execution info
HopGuiWorkflowGraph.ActionAction.ViewExecutionInfo.Tooltip=Look up the
execution information of the \
pipeline or workflow that has this action as its parent.
+HopGuiWorkflowGraph.ContextualAction.BringNoteToFront.Text=Bring to front
+HopGuiWorkflowGraph.ContextualAction.BringNoteToFront.Tooltip=Bring note to
front
HopGuiWorkflowGraph.ContextualAction.Category.Advanced.Text=Advanced
HopGuiWorkflowGraph.ContextualAction.Category.Basic.Text=Basic
HopGuiWorkflowGraph.ContextualAction.Category.Bulk.Text=Bulk
HopGuiWorkflowGraph.ContextualAction.Category.Routing.Text=Routing
+HopGuiWorkflowGraph.ContextualAction.Category.Arrange.Text=Arrange
HopGuiWorkflowGraph.ContextualAction.CopyAction.Text=Copy Action to clipboard
HopGuiWorkflowGraph.ContextualAction.CopyAction.Tooltip=Copy the XML
representation of this Action to the clipboard
HopGuiWorkflowGraph.ContextualAction.CopyNote.Text=Copy Note to clipboard
@@ -70,6 +73,8 @@
HopGuiWorkflowGraph.ContextualAction.ParallelExecution.Text=Parallel execution
HopGuiWorkflowGraph.ContextualAction.ParallelExecution.Tooltip=Enable or
disable parallel execution of next actions
HopGuiWorkflowGraph.ContextualAction.PasteFromClipboard.Text=Paste from the
clipboard
HopGuiWorkflowGraph.ContextualAction.PasteFromClipboard.Tooltip=Paste actions,
notes or a whole workflow from the clipboard
+HopGuiWorkflowGraph.ContextualAction.SendNoteToBack.Text=Send to back
+HopGuiWorkflowGraph.ContextualAction.SendNoteToBack.Tooltip=Send note to back
HopGuiWorkflowGraph.ContextualAction.StartWorkflowHere.Text=Start the workflow
here
HopGuiWorkflowGraph.ContextualAction.StartWorkflowHere.Tooltip=Start the
execution of the workflow from this action.
HopGuiWorkflowGraph.ContextualAction.SuccessHop.Text=Success hop
diff --git a/ui/src/main/resources/ui/images/bring-to-front.svg
b/ui/src/main/resources/ui/images/bring-to-front.svg
new file mode 100644
index 0000000000..98e73a2c29
--- /dev/null
+++ b/ui/src/main/resources/ui/images/bring-to-front.svg
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="800" height="800">
+<path fill="#0E3A5A"
d="M600,240v320c0,22.092-17.909,40-40,40H240c-22.092,0-40-17.908-40-40V240
+ c0-22.091,17.908-40,40-40h320C582.091,200,600,217.909,600,240z"/>
+<path fill="none" stroke="#0E3A5A" stroke-width="42" stroke-linecap="round"
stroke-linejoin="round" d="M600,440h120
+
c22.091,0,40,17.908,40,40v240c0,22.092-17.909,40-40,40H480c-22.092,0-40-17.908-40-40V600"/>
+<path fill="none" stroke="#0E3A5A" stroke-width="42" stroke-linecap="round"
stroke-linejoin="round" d="M200,360
+
H80c-22.092,0-40-17.909-40-40V80c0-22.091,17.908-40,40-40h240c22.091,0,40,17.909,40,40v120"/>
+<path fill="none" stroke="#0E3A5A" stroke-width="42" stroke-linecap="round"
stroke-linejoin="round" d="M600,240
+
v320c0,22.092-17.909,40-40,40H240c-22.092,0-40-17.908-40-40V240c0-22.091,17.908-40,40-40h320C582.091,200,600,217.909,600,240z"
+ />
+</svg>
diff --git a/ui/src/main/resources/ui/images/send-to-back.svg
b/ui/src/main/resources/ui/images/send-to-back.svg
new file mode 100644
index 0000000000..3cba731b5a
--- /dev/null
+++ b/ui/src/main/resources/ui/images/send-to-back.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="800" height="800">
+<path fill="none"
d="M600,240v320c0,22.092-17.909,40-40,40H240c-22.092,0-40-17.908-40-40V240
+ c0-22.091,17.908-40,40-40h320C582.091,200,600,217.909,600,240z"/>
+<path fill="none" stroke="#0E3A5A" stroke-width="42" stroke-linecap="round"
stroke-linejoin="round" d="M600,240
+
v320c0,22.092-17.909,40-40,40H240c-22.092,0-40-17.908-40-40V240c0-22.091,17.908-40,40-40h320C582.091,200,600,217.909,600,240z"
+ />
+<path fill="#0E3A5A" stroke="#0E3A5A" stroke-width="42"
d="M772.487,477.161v253.293
+
c0,17.486-14.191,31.662-31.697,31.662H487.211c-17.506,0-31.697-14.176-31.697-31.662V477.161
+
c0-17.486,14.191-31.661,31.697-31.661h253.578C758.295,445.5,772.487,459.675,772.487,477.161z"/>
+<path fill="#0E3A5A" stroke="#0E3A5A" stroke-width="42"
d="M358.487,71.661v253.293
+
c0,17.486-14.191,31.662-31.697,31.662H73.211c-17.506,0-31.697-14.176-31.697-31.662V71.661C41.514,54.175,55.705,40,73.211,40
+ h253.578C344.295,40,358.487,54.175,358.487,71.661z"/>
+</svg>