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 b895264003 Move the lint error/warning icons to the bottom left #8345
(#8460)
b895264003 is described below
commit b895264003fb13295c22f2f5cc65323dfe513ad4
Author: Nicolas Adment <[email protected]>
AuthorDate: Sat Sep 19 17:35:38 2026 +0200
Move the lint error/warning icons to the bottom left #8345 (#8460)
---
.../src/main/java/org/apache/hop/core/gui/IGc.java | 1 +
.../main/java/org/apache/hop/core/gui/SvgGc.java | 3 ++
.../apache/hop/lint/LintCanvasOverlayHelper.java | 34 ++++++++++--------
.../java/org/apache/hop/lint/LintReportWriter.java | 3 +-
.../org/apache/hop/lint/LintStatusFilePainter.java | 6 ++--
.../hop/lint/LintStatusBadgeCompositeTest.java | 40 ++++++++++++----------
.../delegates/HopGuiPipelineCheckDelegate.java | 12 +++----
.../delegates/HopGuiWorkflowCheckDelegate.java | 11 +++---
.../org/apache/hop/ui/hopgui/shared/SwtGc.java | 1 +
9 files changed, 62 insertions(+), 49 deletions(-)
diff --git a/engine/src/main/java/org/apache/hop/core/gui/IGc.java
b/engine/src/main/java/org/apache/hop/core/gui/IGc.java
index 8fec874d94..ff8ef77530 100644
--- a/engine/src/main/java/org/apache/hop/core/gui/IGc.java
+++ b/engine/src/main/java/org/apache/hop/core/gui/IGc.java
@@ -87,6 +87,7 @@ public interface IGc {
PARALLEL_DISABLED,
BUSY,
WAITING,
+ WARNING,
INJECT,
LOAD_BALANCE,
CHECKPOINT,
diff --git a/engine/src/main/java/org/apache/hop/core/gui/SvgGc.java
b/engine/src/main/java/org/apache/hop/core/gui/SvgGc.java
index 45154d9a15..91909725f6 100644
--- a/engine/src/main/java/org/apache/hop/core/gui/SvgGc.java
+++ b/engine/src/main/java/org/apache/hop/core/gui/SvgGc.java
@@ -81,6 +81,7 @@ public class SvgGc implements IGc {
private static SvgFile imageUnconditionalDisabled;
private static SvgFile imageBusy;
private static SvgFile imageWaiting;
+ private static SvgFile imageWarning;
private static SvgFile imageMissing;
private static SvgFile imageDeprecated;
private static SvgFile imageInject;
@@ -273,6 +274,7 @@ public class SvgGc implements IGc {
new SvgFile("ui/images/unconditional-disabled.svg",
this.getClass().getClassLoader());
imageBusy = new SvgFile("ui/images/busy.svg",
this.getClass().getClassLoader());
imageWaiting = new SvgFile("ui/images/waiting.svg",
this.getClass().getClassLoader());
+ imageWarning = new SvgFile("ui/images/warning.svg",
this.getClass().getClassLoader());
imageInject = new SvgFile("ui/images/inject.svg",
this.getClass().getClassLoader());
imageMissing = new SvgFile("ui/images/missing.svg",
this.getClass().getClassLoader());
imageDeprecated = new SvgFile("ui/images/deprecated.svg",
this.getClass().getClassLoader());
@@ -646,6 +648,7 @@ public class SvgGc implements IGc {
case UNCONDITIONAL_DISABLED -> imageUnconditionalDisabled;
case BUSY -> imageBusy;
case WAITING -> imageWaiting;
+ case WARNING -> imageWarning;
case INJECT -> imageInject;
case ARROW_DEFAULT -> imageArrowDefault;
case ARROW_TRUE -> imageArrowTrue;
diff --git
a/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintCanvasOverlayHelper.java
b/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintCanvasOverlayHelper.java
index 16f6ad71af..129957ea52 100644
---
a/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintCanvasOverlayHelper.java
+++
b/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintCanvasOverlayHelper.java
@@ -105,7 +105,7 @@ public final class LintCanvasOverlayHelper {
* factor for crisp icons on high-DPI displays).
*/
public static int drawTotalsOverlay(
- IGc gc, int x, int y, int errors, int warnings, int infos, float
iconMagnification) {
+ IGc gc, int x, int y, int errors, int warnings, int infos, float
magnification) {
if (gc == null) {
return 0;
}
@@ -147,7 +147,7 @@ public final class LintCanvasOverlayHelper {
iconY,
TOTALS_ICON,
TOTALS_ICON,
- iconMagnification,
+ magnification,
0);
} catch (Exception e) {
// Best-effort: fall back to a colored swatch if the SVG cannot be
rendered.
@@ -266,33 +266,39 @@ public final class LintCanvasOverlayHelper {
}
public static void drawOverlay(
- IGc gc, int x, int y, int iconSize, boolean selected, String severity,
double magnification) {
+ IGc gc, int x, int y, int iconSize, boolean selected, String severity,
float magnification) {
if (gc == null || Utils.isEmpty(severity)) {
return;
}
- float mag = (float) magnification;
-
- int lineWidth = selected ? 3 : 2;
+ int lineWidth = selected ? 3 : 1;
gc.setLineWidth(lineWidth);
if ("ERROR".equalsIgnoreCase(severity)) {
gc.setForeground(IGc.EColor.RED);
- gc.drawRoundRectangle(x - 2, y - 2, iconSize + 3, iconSize + 3, 8, 8);
- int badgeX = x + iconSize - 8;
- int badgeY = y - 4;
+ gc.drawLine(x + iconSize, y + iconSize / 2 - 4, x + iconSize, y +
iconSize / 2 + 4);
+ gc.drawLine(x - 1, y + iconSize / 2 - 4, x - 1, y + iconSize / 2 + 4);
+ gc.drawLine(x + iconSize / 2 - 4, y - 1, x + iconSize / 2 + 4, y - 1);
+ gc.drawLine(x + iconSize / 2 - 4, y + iconSize, x + iconSize / 2 + 4, y
+ iconSize);
+
+ int badgeX = x - 8;
+ int badgeY = y + iconSize - 8;
try {
- gc.drawImage(IGc.EImage.FAILURE, badgeX, badgeY, mag);
+ gc.drawImage(IGc.EImage.ERROR, badgeX, badgeY, magnification);
} catch (Exception ignored) {
// Icon drawing is best-effort on the canvas overlay
}
} else if ("WARNING".equalsIgnoreCase(severity)) {
gc.setForeground(IGc.EColor.YELLOW);
- gc.drawRoundRectangle(x - 2, y - 2, iconSize + 3, iconSize + 3, 8, 8);
- int badgeX = x + iconSize - 8;
- int badgeY = y - 4;
+ gc.drawLine(x + iconSize, y + iconSize / 2 - 4, x + iconSize, y +
iconSize / 2 + 4);
+ gc.drawLine(x - 1, y + iconSize / 2 - 4, x - 1, y + iconSize / 2 + 4);
+ gc.drawLine(x + iconSize / 2 - 4, y - 1, x + iconSize / 2 + 4, y - 1);
+ gc.drawLine(x + iconSize / 2 - 4, y + iconSize, x + iconSize / 2 + 4, y
+ iconSize);
+
+ int badgeX = x - 8;
+ int badgeY = y + iconSize - 8;
try {
- gc.drawImage(IGc.EImage.INFO, badgeX, badgeY, mag);
+ gc.drawImage(IGc.EImage.WARNING, badgeX, badgeY, magnification);
} catch (Exception ignored) {
// Icon drawing is best-effort on the canvas overlay
}
diff --git
a/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintReportWriter.java
b/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintReportWriter.java
index 4d9e92eeec..5217cd35d2 100644
--- a/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintReportWriter.java
+++ b/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintReportWriter.java
@@ -208,7 +208,8 @@ public final class LintReportWriter {
try {
Path path = Paths.get(fileName);
if (path.isAbsolute() && path.startsWith(baseDirectory)) {
- return baseDirectory.relativize(path).toString();
+ // Reports are read on other machines and SARIF wants a URI: always
use forward slashes.
+ return baseDirectory.relativize(path).toString().replace('\\', '/');
}
} catch (Exception ignored) {
// Not a real path (metadata findings use labels like "connection:
prod"); pass it through.
diff --git
a/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintStatusFilePainter.java
b/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintStatusFilePainter.java
index 8c7d557718..ec02dde8e9 100644
---
a/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintStatusFilePainter.java
+++
b/plugins/misc/lint/src/main/java/org/apache/hop/lint/LintStatusFilePainter.java
@@ -398,8 +398,8 @@ public class LintStatusFilePainter implements
IExplorerFilePaintListener {
}
/**
- * The base icon with the badge scaled into its bottom right corner, blended
over whatever the
- * base has there rather than punched through it, so a badge with soft edges
does not leave a hard
+ * The base icon with the badge scaled into its bottom left corner, blended
over whatever the base
+ * has there rather than punched through it, so a badge with soft edges does
not leave a hard
* outline. What the base leaves transparent stays transparent: the tree
paints its own background
* behind the icon.
*
@@ -410,7 +410,7 @@ public class LintStatusFilePainter implements
IExplorerFilePaintListener {
ImageData composite = withPerPixelAlpha(baseData);
ImageData scaled = badgeData.scaledTo(badgeSize, badgeSize);
ImageData scaledMask = transparencyMask(scaled);
- int offsetX = composite.width - badgeSize - margin;
+ int offsetX = margin;
int offsetY = composite.height - badgeSize - margin;
for (int y = 0; y < badgeSize; y++) {
diff --git
a/plugins/misc/lint/src/test/java/org/apache/hop/lint/LintStatusBadgeCompositeTest.java
b/plugins/misc/lint/src/test/java/org/apache/hop/lint/LintStatusBadgeCompositeTest.java
index d25fb1290a..42a92d8662 100644
---
a/plugins/misc/lint/src/test/java/org/apache/hop/lint/LintStatusBadgeCompositeTest.java
+++
b/plugins/misc/lint/src/test/java/org/apache/hop/lint/LintStatusBadgeCompositeTest.java
@@ -54,18 +54,20 @@ class LintStatusBadgeCompositeTest {
}
@Test
- @DisplayName("the badge lands in the bottom right corner and leaves the rest
of the icon alone")
+ @DisplayName("the badge lands in the bottom left corner and leaves the rest
of the icon alone")
void badgeIsCompositedIntoTheCorner() {
ImageData composite =
LintStatusFilePainter.withBadge(icon(16, BASE_COLOR, 255), icon(8,
BADGE_COLOR, 255), 8, 1);
assertEquals(16, composite.width);
assertEquals(16, composite.height);
- // One pixel of margin is kept, so the very last column and row stay the
base icon.
- assertEquals(BADGE_COLOR, colorAt(composite, 14, 14));
- assertEquals(BASE_COLOR, colorAt(composite, 15, 15));
- assertEquals(BASE_COLOR, colorAt(composite, 0, 0));
- assertEquals(BASE_COLOR, colorAt(composite, 6, 6));
+ // One pixel of margin is kept, so the very first column and last row stay
the base icon.
+ assertEquals(BADGE_COLOR, colorAt(composite, 1, 14));
+ assertEquals(BASE_COLOR, colorAt(composite, 0, 15));
+ assertEquals(BASE_COLOR, colorAt(composite, 15, 0));
+ assertEquals(BASE_COLOR, colorAt(composite, 9, 6));
+ // The bottom right corner is no longer where the badge goes.
+ assertEquals(BASE_COLOR, colorAt(composite, 14, 14));
}
@Test
@@ -74,8 +76,8 @@ class LintStatusBadgeCompositeTest {
ImageData composite =
LintStatusFilePainter.withBadge(icon(16, BASE_COLOR, 255), icon(8,
BADGE_COLOR, 0), 8, 1);
- assertEquals(BASE_COLOR, colorAt(composite, 14, 14));
- assertEquals(255, composite.getAlpha(14, 14));
+ assertEquals(BASE_COLOR, colorAt(composite, 1, 14));
+ assertEquals(255, composite.getAlpha(1, 14));
}
@Test
@@ -86,8 +88,8 @@ class LintStatusBadgeCompositeTest {
assertEquals(0, composite.getAlpha(0, 0));
// Where the badge is opaque it wins outright, transparent base or not.
- assertEquals(255, composite.getAlpha(14, 14));
- assertEquals(BADGE_COLOR, colorAt(composite, 14, 14));
+ assertEquals(255, composite.getAlpha(1, 14));
+ assertEquals(BADGE_COLOR, colorAt(composite, 1, 14));
}
/** Palette icons say "transparent" with a pixel value rather than an alpha
channel. */
@@ -127,15 +129,15 @@ class LintStatusBadgeCompositeTest {
assertEquals(32, at200.width);
// The badge corner of the 100% icon, at twice the scale, is still the
badge corner.
- assertEquals(BADGE_COLOR, colorAt(at100, 7, 7));
- assertEquals(BADGE_COLOR, colorAt(at200, 14, 14));
+ assertEquals(BADGE_COLOR, colorAt(at100, 8, 7));
+ assertEquals(BADGE_COLOR, colorAt(at200, 17, 14));
// And so is the last pixel before the margin.
- assertEquals(BADGE_COLOR, colorAt(at100, 14, 14));
- assertEquals(BADGE_COLOR, colorAt(at200, 29, 29));
+ assertEquals(BADGE_COLOR, colorAt(at100, 1, 14));
+ assertEquals(BADGE_COLOR, colorAt(at200, 2, 29));
// The margin itself stays the base icon at both zooms.
- assertEquals(BASE_COLOR, colorAt(at100, 15, 15));
- assertEquals(BASE_COLOR, colorAt(at200, 30, 30));
- assertEquals(BASE_COLOR, colorAt(at200, 31, 31));
+ assertEquals(BASE_COLOR, colorAt(at100, 0, 15));
+ assertEquals(BASE_COLOR, colorAt(at200, 1, 30));
+ assertEquals(BASE_COLOR, colorAt(at200, 0, 31));
}
@Test
@@ -146,10 +148,10 @@ class LintStatusBadgeCompositeTest {
icon(16, new RGB(0, 0, 0), 255), icon(8, new RGB(255, 255, 255),
128), 8, 1);
// Half of white over black, opaque either way.
- RGB blended = colorAt(composite, 14, 14);
+ RGB blended = colorAt(composite, 1, 14);
assertEquals(128, blended.red);
assertEquals(128, blended.green);
assertEquals(128, blended.blue);
- assertEquals(255, composite.getAlpha(14, 14));
+ assertEquals(255, composite.getAlpha(1, 14));
}
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/delegates/HopGuiPipelineCheckDelegate.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/delegates/HopGuiPipelineCheckDelegate.java
index ea6a1c1d48..56ef579fe1 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/delegates/HopGuiPipelineCheckDelegate.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/delegates/HopGuiPipelineCheckDelegate.java
@@ -27,12 +27,12 @@ import org.apache.hop.core.ICheckResult;
import org.apache.hop.core.ICheckResultSource;
import org.apache.hop.core.IProgressMonitor;
import org.apache.hop.core.Props;
+import org.apache.hop.core.SwtUniversalImage;
import org.apache.hop.core.gui.plugin.GuiPlugin;
import org.apache.hop.core.gui.plugin.toolbar.GuiToolbarElement;
import org.apache.hop.i18n.BaseMessages;
import org.apache.hop.pipeline.PipelineMeta;
import org.apache.hop.pipeline.transform.TransformMeta;
-import org.apache.hop.ui.core.ConstUi;
import org.apache.hop.ui.core.PropsUi;
import org.apache.hop.ui.core.dialog.ErrorDialog;
import org.apache.hop.ui.core.dialog.ProgressMonitorDialog;
@@ -275,11 +275,10 @@ public class HopGuiPipelineCheckDelegate {
parentItem.setData(source);
if (source instanceof TransformMeta transform) {
- Image image =
- GuiResource.getInstance()
- .getSwtImageTransform(transform.getPluginId())
- .getAsBitmapForSize(
- hopGui.getDisplay(), ConstUi.MEDIUM_ICON_SIZE,
ConstUi.MEDIUM_ICON_SIZE);
+ SwtUniversalImage swtImage =
+
GuiResource.getInstance().getSwtImageTransform(transform.getPluginId());
+ Image image = GuiResource.getInstance().getSmallIcon(swtImage);
+
if (image != null) {
parentItem.setImage(image);
}
@@ -306,6 +305,7 @@ public class HopGuiPipelineCheckDelegate {
case ICheckResult.TYPE_RESULT_OK ->
GuiResource.getInstance().getImageTrue();
case ICheckResult.TYPE_RESULT_ERROR ->
GuiResource.getInstance().getImageError();
case ICheckResult.TYPE_RESULT_WARNING ->
GuiResource.getInstance().getImageWarning();
+ case ICheckResult.TYPE_RESULT_COMMENT ->
GuiResource.getInstance().getImageInfo();
default -> null;
};
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/delegates/HopGuiWorkflowCheckDelegate.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/delegates/HopGuiWorkflowCheckDelegate.java
index 59ab41e017..98c77b93f8 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/delegates/HopGuiWorkflowCheckDelegate.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/delegates/HopGuiWorkflowCheckDelegate.java
@@ -26,10 +26,10 @@ import lombok.Getter;
import org.apache.hop.core.ICheckResult;
import org.apache.hop.core.ICheckResultSource;
import org.apache.hop.core.Props;
+import org.apache.hop.core.SwtUniversalImage;
import org.apache.hop.core.gui.plugin.GuiPlugin;
import org.apache.hop.core.gui.plugin.toolbar.GuiToolbarElement;
import org.apache.hop.i18n.BaseMessages;
-import org.apache.hop.ui.core.ConstUi;
import org.apache.hop.ui.core.PropsUi;
import org.apache.hop.ui.core.dialog.ErrorDialog;
import org.apache.hop.ui.core.dialog.ProgressMonitorDialog;
@@ -249,11 +249,9 @@ public class HopGuiWorkflowCheckDelegate {
parentItem.setData(source);
if (source instanceof IAction action) {
- Image image =
- GuiResource.getInstance()
- .getSwtImageAction(action.getPluginId())
- .getAsBitmapForSize(
- hopGui.getDisplay(), ConstUi.MEDIUM_ICON_SIZE,
ConstUi.MEDIUM_ICON_SIZE);
+ SwtUniversalImage swtImage =
+
GuiResource.getInstance().getSwtImageAction(action.getPluginId());
+ Image image = GuiResource.getInstance().getSmallIcon(swtImage);
if (image != null) {
parentItem.setImage(image);
}
@@ -281,6 +279,7 @@ public class HopGuiWorkflowCheckDelegate {
case ICheckResult.TYPE_RESULT_OK ->
GuiResource.getInstance().getImageTrue();
case ICheckResult.TYPE_RESULT_ERROR ->
GuiResource.getInstance().getImageError();
case ICheckResult.TYPE_RESULT_WARNING ->
GuiResource.getInstance().getImageWarning();
+ case ICheckResult.TYPE_RESULT_COMMENT ->
GuiResource.getInstance().getImageInfo();
default -> null;
};
}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/shared/SwtGc.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/shared/SwtGc.java
index 4ec4264b9a..59aeb296e3 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/shared/SwtGc.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/shared/SwtGc.java
@@ -233,6 +233,7 @@ public class SwtGc implements IGc {
case UNCONDITIONAL_DISABLED ->
GuiResource.getInstance().getSwtImageUnconditionalDisabled();
case BUSY -> GuiResource.getInstance().getSwtImageBusy();
case WAITING -> GuiResource.getInstance().getSwtImageWaiting();
+ case WARNING -> GuiResource.getInstance().getSwtImageWarning();
case INJECT -> GuiResource.getInstance().getSwtImageInject();
case ARROW_DEFAULT ->
GuiResource.getInstance().getSwtImageArrowDefault();
case ARROW_TRUE -> GuiResource.getInstance().getSwtImageArrowTrue();