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();

Reply via email to