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 d07c767358 cleanup and simplify hop web for tab rendering in Linux and
Hop Web. … (#6247)
d07c767358 is described below
commit d07c767358b4382e320632276acae7e974e9017f
Author: Bart Maertens <[email protected]>
AuthorDate: Tue Dec 23 13:34:53 2025 +0000
cleanup and simplify hop web for tab rendering in Linux and Hop Web. …
(#6247)
* cleanup and simplify hop web for tab rendering in Linux and Hop Web.
fixes #6246
* spotless update. #6246
---
docker/unified.Dockerfile | 14 ---
.../apache/hop/ui/core/SafeCTabFolderRenderer.java | 117 +++++++++++++++++++++
.../main/java/org/apache/hop/ui/core/PropsUi.java | 29 +++--
.../apache/hop/ui/core/SafeCTabFolderRenderer.java | 85 ---------------
4 files changed, 138 insertions(+), 107 deletions(-)
diff --git a/docker/unified.Dockerfile b/docker/unified.Dockerfile
index 64c48df365..d1bf099fac 100644
--- a/docker/unified.Dockerfile
+++ b/docker/unified.Dockerfile
@@ -189,20 +189,6 @@ RUN mkdir -p /build/hop-web-prepared/webapps/ROOT && \
cp -r /build/assemblies/client/target/hop/lib/beam/*
/build/hop-web-prepared/webapps/ROOT/WEB-INF/lib/ && \
cp -r /build/assemblies/client/target/hop/lib/core/*
/build/hop-web-prepared/webapps/ROOT/WEB-INF/lib/ && \
rm /build/hop-web-prepared/webapps/ROOT/WEB-INF/lib/hop-ui-rcp* && \
- # Remove SafeCTabFolderRenderer.class from hop-ui JAR - it extends
CTabFolderRenderer
- # which doesn't exist in RAP/web mode, causing NoClassDefFoundError
- for jar in /build/hop-web-prepared/webapps/ROOT/WEB-INF/lib/hop-ui-*.jar;
do \
- if [ -f "$jar" ]; then \
- cd /tmp && \
- unzip -q "$jar" -d hop-ui-temp && \
- rm -f
hop-ui-temp/org/apache/hop/ui/core/SafeCTabFolderRenderer.class && \
- rm -f "$jar" && \
- cd hop-ui-temp && \
- zip -q -r "$jar" . && \
- cd /build && \
- rm -rf /tmp/hop-ui-temp; \
- fi; \
- done && \
mkdir -p /build/hop-web-prepared/bin && \
cp -r /build/docker/resources/run-web.sh
/build/hop-web-prepared/bin/run-web.sh
diff --git
a/rcp/src/main/java/org/apache/hop/ui/core/SafeCTabFolderRenderer.java
b/rcp/src/main/java/org/apache/hop/ui/core/SafeCTabFolderRenderer.java
new file mode 100644
index 0000000000..d3ea3a50c9
--- /dev/null
+++ b/rcp/src/main/java/org/apache/hop/ui/core/SafeCTabFolderRenderer.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.core;
+
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabFolderRenderer;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+
+/**
+ * A safe CTabFolderRenderer that catches IllegalArgumentException when
drawing tab images. This
+ * prevents crashes on some Linux desktop environments (e.g., KDE
Plasma/Wayland) where images may
+ * be invalid or disposed during rendering. When an image drawing error
occurs, the image is skipped
+ * but the text is still rendered.
+ *
+ * <p>This class is in the RCP module (desktop-specific) and loaded via
reflection from
+ * PropsUi.ensureSafeRenderer(). Since that method short-circuits in web mode
(isWeb() check), and
+ * this class is not included in web builds (hop-ui-rcp is excluded), it will
never be loaded in
+ * RAP/web mode.
+ */
+public class SafeCTabFolderRenderer extends CTabFolderRenderer {
+ private final CTabFolder parentFolder;
+
+ public SafeCTabFolderRenderer(CTabFolder parent) {
+ super(parent);
+ this.parentFolder = parent;
+ }
+
+ @Override
+ protected void draw(int part, int state, Rectangle bounds, GC gc) {
+ if (bounds != null && (bounds.width <= 0 || bounds.height <= 0)) {
+ return;
+ }
+
+ // Check for invalid/disposed images before drawing to prevent
IllegalArgumentException
+ // on Linux environments (e.g., KDE Plasma/Wayland) where images may be
invalid or disposed
+ Image[] savedImages = null;
+ boolean hadInvalidImages = false;
+
+ if (parentFolder != null && !parentFolder.isDisposed()) {
+ CTabItem[] items = parentFolder.getItems();
+ savedImages = new Image[items.length];
+
+ // Check each tab item's image for validity before drawing
+ for (int i = 0; i < items.length; i++) {
+ Image image = items[i].getImage();
+ savedImages[i] = image;
+
+ // If image is disposed/invalid, temporarily remove it to prevent
rendering errors
+ if (image != null && image.isDisposed()) {
+ items[i].setImage(null);
+ hadInvalidImages = true;
+ }
+ }
+ }
+
+ try {
+ super.draw(part, state, bounds, gc);
+ } catch (IllegalArgumentException e) {
+ // If image drawing still fails (e.g., image becomes invalid during
drawing),
+ // temporarily remove all images and redraw to allow text to be rendered
+ if (parentFolder != null && !parentFolder.isDisposed()) {
+ CTabItem[] items = parentFolder.getItems();
+
+ // Clear all images that weren't already cleared
+ for (int i = 0; i < items.length && savedImages != null && i <
savedImages.length; i++) {
+ if (savedImages[i] != null && items[i].getImage() != null) {
+ items[i].setImage(null);
+ }
+ }
+
+ try {
+ // Redraw without images - this should succeed and render the text
+ super.draw(part, state, bounds, gc);
+ } finally {
+ // Restore images (even if they're invalid, we'll catch it next time)
+ restoreImages(items, savedImages);
+ }
+ }
+ } finally {
+ // Restore images that were temporarily removed due to being disposed
+ if (hadInvalidImages && parentFolder != null &&
!parentFolder.isDisposed()) {
+ restoreImages(parentFolder.getItems(), savedImages);
+ }
+ }
+ }
+
+ /** Restores images to tab items, skipping any that are disposed */
+ private void restoreImages(CTabItem[] items, Image[] savedImages) {
+ if (items == null || savedImages == null) {
+ return;
+ }
+
+ for (int i = 0; i < items.length && i < savedImages.length; i++) {
+ if (savedImages[i] != null && !savedImages[i].isDisposed()) {
+ items[i].setImage(savedImages[i]);
+ }
+ }
+ }
+}
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 9fa1db70ac..03a9869072 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
@@ -522,30 +522,43 @@ public class PropsUi extends Props {
* on Wayland) where images may be invalid or disposed. Only applied on
Linux to avoid any
* potential impact on unaffected platforms.
*
+ * <p>SafeCTabFolderRenderer is in the RCP module (desktop-specific) and
loaded via reflection.
+ * Since this method short-circuits in web mode and SafeCTabFolderRenderer
is not included in web
+ * builds (hop-ui-rcp is excluded), it will never be loaded in RAP/web mode.
+ *
* @param tabFolder the CTabFolder to protect
*/
private static void ensureSafeRenderer(CTabFolder tabFolder) {
- // CTabFolderRenderer and SafeCTabFolderRenderer are not available in RAP
(web mode),
- // so skip entirely. The class is also removed from the hop-ui JAR during
Docker build.
- // Use reflection to avoid compile-time class resolution that would cause
NoClassDefFoundError
- // in web mode when the class doesn't exist in the JAR.
+ // CTabFolderRenderer is not available in RAP (web mode), so skip entirely.
+ // SafeCTabFolderRenderer is in the RCP module (not included in web
builds), so it's never
+ // available in web mode.
if (EnvironmentUtils.getInstance().isWeb()) {
return;
}
// Only apply safe renderer on Linux where the issue occurs
if (Const.isLinux()) {
try {
- // Use reflection to avoid compile-time dependency on
SafeCTabFolderRenderer
- // This prevents Java's bytecode verifier from trying to resolve the
class at load time
+ // Use reflection to load SafeCTabFolderRenderer from the RCP module
(desktop-specific).
+ // This avoids compile-time dependencies and ensures the class isn't
loaded in web mode
+ // (where hop-ui-rcp is excluded from the build).
Class<?> rendererClass =
Class.forName("org.apache.hop.ui.core.SafeCTabFolderRenderer");
Object currentRenderer = tabFolder.getRenderer();
if (currentRenderer == null ||
!rendererClass.isInstance(currentRenderer)) {
Object safeRenderer =
rendererClass.getConstructor(CTabFolder.class).newInstance(tabFolder);
- tabFolder.setRenderer((org.eclipse.swt.custom.CTabFolderRenderer)
safeRenderer);
+ // Use reflection to call setRenderer to avoid compile-time
dependency on
+ // CTabFolderRenderer which doesn't exist in RAP/web mode
+ Class<?> rendererParamClass =
Class.forName("org.eclipse.swt.custom.CTabFolderRenderer");
+ java.lang.reflect.Method setRendererMethod =
+ CTabFolder.class.getMethod("setRenderer", rendererParamClass);
+ setRendererMethod.invoke(tabFolder, safeRenderer);
}
+ } catch (ClassNotFoundException e) {
+ // SafeCTabFolderRenderer not available (e.g., in web builds where
hop-ui-rcp is excluded)
+ // This is expected and safe to ignore
} catch (Exception e) {
- // If SafeCTabFolderRenderer can't be loaded, just continue without
the safe renderer
+ // If CTabFolderRenderer can't be loaded or setRenderer fails, just
continue without
+ // the safe renderer
LogChannel.GENERAL.logDetailed("Could not apply
SafeCTabFolderRenderer: " + e.getMessage());
}
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/core/SafeCTabFolderRenderer.java
b/ui/src/main/java/org/apache/hop/ui/core/SafeCTabFolderRenderer.java
deleted file mode 100644
index 7d5a3830cc..0000000000
--- a/ui/src/main/java/org/apache/hop/ui/core/SafeCTabFolderRenderer.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hop.ui.core;
-
-import org.eclipse.swt.custom.CTabFolder;
-import org.eclipse.swt.custom.CTabFolderRenderer;
-import org.eclipse.swt.custom.CTabItem;
-import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Rectangle;
-
-/**
- * A safe CTabFolderRenderer that catches IllegalArgumentException when
drawing tab images. This
- * prevents crashes on some Linux desktop environments where images may be
invalid or disposed
- * during rendering. When an image drawing error occurs, the image is skipped
but the text is still
- * rendered.
- *
- * <p>This class is in a separate file to avoid loading CTabFolderRenderer
(which doesn't exist in
- * RAP/web mode) when PropsUi is loaded. The class is only instantiated on
Linux desktop
- * environments where it's needed.
- */
-public class SafeCTabFolderRenderer extends CTabFolderRenderer {
- private final CTabFolder parentFolder;
-
- public SafeCTabFolderRenderer(CTabFolder parent) {
- super(parent);
- this.parentFolder = parent;
- }
-
- @Override
- protected void draw(int part, int state, Rectangle bounds, GC gc) {
- if (bounds != null && (bounds.width <= 0 || bounds.height <= 0)) {
- return;
- }
- try {
- super.draw(part, state, bounds, gc);
- } catch (IllegalArgumentException e) {
- // If image drawing fails, temporarily remove images from tab items and
redraw
- // This allows text to be rendered even when images are invalid
- if (parentFolder != null && !parentFolder.isDisposed()) {
- CTabItem[] items = parentFolder.getItems();
- Image[] savedImages = new Image[items.length];
- boolean hadImages = false;
-
- // Save and temporarily clear images
- for (int i = 0; i < items.length; i++) {
- savedImages[i] = items[i].getImage();
- if (savedImages[i] != null) {
- items[i].setImage(null);
- hadImages = true;
- }
- }
-
- if (hadImages) {
- try {
- // Redraw without images - this should succeed and render the text
- super.draw(part, state, bounds, gc);
- } finally {
- // Restore images (even if they're invalid, we'll catch the
exception next time)
- for (int i = 0; i < items.length; i++) {
- if (savedImages[i] != null) {
- items[i].setImage(savedImages[i]);
- }
- }
- }
- }
- }
- }
- }
-}