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 2cd541279d support for html and pdf files in Hop Gui #6354 (#6365)
2cd541279d is described below
commit 2cd541279da8dcff5c34dcd256d21daf4cb00ec9
Author: Bart Maertens <[email protected]>
AuthorDate: Tue Jan 13 15:47:50 2026 +0000
support for html and pdf files in Hop Gui #6354 (#6365)
* add support for HTML and PDF files in Hop Gui. #6354
* i18n updates. #6354
---
.../transforms/types/HtmlExplorerFileType.java | 87 ++++++++++
.../types/HtmlExplorerFileTypeHandler.java | 186 +++++++++++++++++++++
.../transforms/types/HtmlOpenAsTextPlugin.java | 86 ++++++++++
.../transforms/types/PdfExplorerFileType.java | 60 +++++++
.../types/PdfExplorerFileTypeHandler.java | 117 +++++++++++++
.../hopgui/file/pipeline/HopPipelineFileType.java | 5 +-
.../explorer/config/ExplorerPerspectiveConfig.java | 11 ++
.../config/ExplorerPerspectiveConfigPlugin.java | 32 ++++
.../java/org/apache/hop/ui/util/HelpUtils.java | 24 ++-
.../config/messages/messages_en_US.properties | 3 +
.../explorer/messages/messages_en_US.properties | 3 +-
ui/src/main/resources/ui/images/html.svg | 9 +
ui/src/main/resources/ui/images/pdf.svg | 9 +
13 files changed, 628 insertions(+), 4 deletions(-)
diff --git
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/HtmlExplorerFileType.java
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/HtmlExplorerFileType.java
new file mode 100644
index 0000000000..3addf9545b
--- /dev/null
+++
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/HtmlExplorerFileType.java
@@ -0,0 +1,87 @@
+/*
+ * 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.pipeline.transforms.types;
+
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.HopFileTypePlugin;
+import org.apache.hop.ui.hopgui.file.IHopFileType;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+import org.apache.hop.ui.hopgui.file.empty.EmptyHopFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerFile;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
+import
org.apache.hop.ui.hopgui.perspective.explorer.file.capabilities.FileTypeCapabilities;
+import
org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileType;
+
+@HopFileTypePlugin(
+ id = "HtmlExplorerFileType",
+ name = "HTML File Type",
+ description = "HTML file handling in the explorer perspective",
+ image = "ui/images/html.svg")
+public class HtmlExplorerFileType extends
BaseExplorerFileType<HtmlExplorerFileTypeHandler> {
+
+ public HtmlExplorerFileType() {
+ super(
+ "HTML File",
+ ".html",
+ new String[] {"*.html", "*.htm"},
+ new String[] {"HTML files"},
+ FileTypeCapabilities.getCapabilities(
+ IHopFileType.CAPABILITY_SAVE,
+ IHopFileType.CAPABILITY_SAVE_AS,
+ IHopFileType.CAPABILITY_CLOSE,
+ IHopFileType.CAPABILITY_FILE_HISTORY,
+ IHopFileType.CAPABILITY_COPY,
+ IHopFileType.CAPABILITY_SELECT));
+ }
+
+ @Override
+ public HtmlExplorerFileTypeHandler createFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file) {
+ return new HtmlExplorerFileTypeHandler(hopGui, perspective, file);
+ }
+
+ @Override
+ public IHopFileTypeHandler newFile(HopGui hopGui, IVariables
parentVariableSpace)
+ throws HopException {
+ return new EmptyHopFileTypeHandler();
+ }
+
+ @Override
+ public HtmlExplorerFileTypeHandler openFile(HopGui hopGui, String filename,
IVariables variables)
+ throws HopException {
+ String resolvedFilename = variables.resolve(filename);
+ if (resolvedFilename.toLowerCase().startsWith("http://")
+ || resolvedFilename.toLowerCase().startsWith("https://")) {
+ // Create handler without VFS checks for URLs
+ //
+ ExplorerFile explorerFile = new ExplorerFile();
+ explorerFile.setName(resolvedFilename);
+ explorerFile.setFilename(resolvedFilename);
+ explorerFile.setFileType(this);
+
+ ExplorerPerspective perspective = ExplorerPerspective.getInstance();
+ HtmlExplorerFileTypeHandler handler =
+ createFileTypeHandler(hopGui, perspective, explorerFile);
+ perspective.addFile(handler);
+ return handler;
+ }
+ return super.openFile(hopGui, filename, variables);
+ }
+}
diff --git
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/HtmlExplorerFileTypeHandler.java
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/HtmlExplorerFileTypeHandler.java
new file mode 100644
index 0000000000..b408cea05e
--- /dev/null
+++
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/HtmlExplorerFileTypeHandler.java
@@ -0,0 +1,186 @@
+/*
+ * 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.pipeline.transforms.types;
+
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.vfs2.FileObject;
+import org.apache.hop.core.Const;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.core.vfs.HopVfs;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.core.dialog.MessageBox;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerFile;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
+import
org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileTypeHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+
+/** This handles an HTML file in the file explorer perspective: open, save,
... */
+public class HtmlExplorerFileTypeHandler extends BaseExplorerFileTypeHandler {
+
+ private Browser wBrowser;
+ private String originalHtmlContent;
+
+ public HtmlExplorerFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile
explorerFile) {
+ super(hopGui, perspective, explorerFile);
+ }
+
+ @Override
+ public void renderFile(Composite composite) {
+ // Render the file by showing the HTML content in a browser widget
+ //
+ wBrowser = new Browser(composite, SWT.NONE);
+ PropsUi.setLook(wBrowser);
+ FormData fdBrowser = new FormData();
+ fdBrowser.left = new FormAttachment(0, 0);
+ fdBrowser.right = new FormAttachment(100, 0);
+ fdBrowser.top = new FormAttachment(0, 0);
+ fdBrowser.bottom = new FormAttachment(100, 0);
+ wBrowser.setLayoutData(fdBrowser);
+
+ reload();
+ }
+
+ @Override
+ public void save() throws HopException {
+ try {
+ // Save the current HTML content
+ //
+ String filename = explorerFile.getFilename();
+
+ boolean fileExist = HopVfs.fileExists(filename);
+
+ // Save the HTML content
+ // Note: We save the original content since Browser widget doesn't
easily expose
+ // edited content. For full editing support, a source view would be
needed.
+ //
+ if (originalHtmlContent != null) {
+ try (OutputStream outputStream = HopVfs.getOutputStream(filename,
false)) {
+
outputStream.write(originalHtmlContent.getBytes(StandardCharsets.UTF_8));
+ outputStream.flush();
+ }
+ } else {
+ throw new HopException("No HTML content to save");
+ }
+
+ this.clearChanged();
+
+ // Update menu options, tab and tree item
+ updateGui();
+
+ // If we create a new file, refresh the explorer perspective tree
+ if (!fileExist) {
+ perspective.refresh();
+ }
+ } catch (Exception e) {
+ throw new HopException("Unable to save HTML file '" +
explorerFile.getFilename() + "'", e);
+ }
+ }
+
+ @Override
+ public void saveAs(String filename) throws HopException {
+ try {
+ // Enforce file extension
+ if (!filename.toLowerCase().endsWith(".html") &&
!filename.toLowerCase().endsWith(".htm")) {
+ filename = filename + ".html";
+ }
+
+ // Normalize file name
+ filename = HopVfs.normalize(filename);
+
+ FileObject fileObject = HopVfs.getFileObject(filename);
+ if (fileObject.exists()) {
+ MessageBox box =
+ new MessageBox(hopGui.getActiveShell(), SWT.YES | SWT.NO |
SWT.ICON_QUESTION);
+ box.setText("Overwrite?");
+ box.setMessage("Are you sure you want to overwrite file '" + filename
+ "'?");
+ int answer = box.open();
+ if ((answer & SWT.YES) == 0) {
+ return;
+ }
+ }
+
+ setFilename(filename);
+
+ save();
+ hopGui.fileRefreshDelegate.register(filename, this);
+ } catch (Exception e) {
+ throw new HopException("Error validating file existence for '" +
filename + "'", e);
+ }
+ }
+
+ @Override
+ public void reload() {
+ try {
+ String filename = explorerFile.getFilename();
+ if (filename.toLowerCase().startsWith("http://")
+ || filename.toLowerCase().startsWith("https://")) {
+ wBrowser.setUrl(filename);
+ clearChanged();
+ return;
+ }
+
+ // Read HTML content from file
+ String htmlContent = readTextFileContent("UTF-8");
+ originalHtmlContent = Const.NVL(htmlContent, "");
+
+ // Display HTML in browser widget
+ wBrowser.setText(originalHtmlContent);
+
+ // Clear any change flags since we just reloaded
+ clearChanged();
+ } catch (Exception e) {
+ LogChannel.UI.logError(
+ "Error reading contents of HTML file '" + explorerFile.getFilename()
+ "'", e);
+ // Show error in browser
+ wBrowser.setText(
+ "<html><body><h1>Error loading HTML file</h1><p>"
+ + Const.NVL(e.getMessage(), "Unknown error")
+ + "</p></body></html>");
+ }
+ }
+
+ @Override
+ public void selectAll() {
+ // Browser widget doesn't support selectAll in the same way as Text widget
+ // Could use JavaScript:
wBrowser.execute("document.execCommand('selectAll',
+ // false, null);");
+ // For now, do nothing
+ }
+
+ @Override
+ public void unselectAll() {
+ // Browser widget doesn't support unselectAll
+ // For now, do nothing
+ }
+
+ @Override
+ public void copySelectedToClipboard() {
+ // Browser widget doesn't directly support copy to clipboard
+ // Could use JavaScript: wBrowser.execute("document.execCommand('copy',
false,
+ // null);");
+ // For now, do nothing
+ }
+}
diff --git
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/HtmlOpenAsTextPlugin.java
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/HtmlOpenAsTextPlugin.java
new file mode 100644
index 0000000000..2d952e800b
--- /dev/null
+++
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/HtmlOpenAsTextPlugin.java
@@ -0,0 +1,86 @@
+/*
+ * 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.pipeline.transforms.types;
+
+import org.apache.hop.core.gui.plugin.GuiPlugin;
+import org.apache.hop.core.gui.plugin.menu.GuiMenuElement;
+import org.apache.hop.core.vfs.HopVfs;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.HopFileTypeRegistry;
+import org.apache.hop.ui.hopgui.file.IHopFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerFile;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.IExplorerFileType;
+
+@GuiPlugin
+public class HtmlOpenAsTextPlugin {
+
+ @GuiMenuElement(
+ root = ExplorerPerspective.GUI_PLUGIN_CONTEXT_MENU_PARENT_ID,
+ id = "ExplorerPerspective-Html-OpenAsText",
+ label =
+
"i18n:org.apache.hop.ui.hopgui.perspective.explorer:ExplorerPerspective.ToolbarElement.OpenAsText.Label",
+ image = "textfile.svg",
+ parentId = ExplorerPerspective.GUI_PLUGIN_CONTEXT_MENU_PARENT_ID,
+ separator = true)
+ public void openAsText() {
+ ExplorerPerspective perspective = ExplorerPerspective.getInstance();
+ ExplorerFile explorerFile = perspective.getSelectedFile();
+
+ if (explorerFile == null) {
+ return;
+ }
+
+ String filename = explorerFile.getFilename();
+ if (filename == null || !filename.toLowerCase().endsWith(".html")) {
+ return;
+ }
+
+ try {
+ HopGui hopGui = HopGui.getInstance();
+
+ // Find the text file type handler (by using a dummy .txt filename)
+ IHopFileType hopFileType =
HopFileTypeRegistry.getInstance().findHopFileType("dummy.txt");
+
+ if (hopFileType instanceof IExplorerFileType) {
+ IExplorerFileType textFileType = (IExplorerFileType) hopFileType;
+
+ // Create a new ExplorerFile structure but force it to be the Text
file type
+ ExplorerFile textExplorerFile = new ExplorerFile();
+ // Use the file URI to ensure a unique string key for the tab, but
pointing to
+ // the same physical file
+ // This avoids the "Duplicate Tab" check in ExplorerPerspective while
using a
+ // valid file path that won't crash Hop
+ String uniqueName = HopVfs.getFileObject(filename).getName().getURI();
+ textExplorerFile.setFilename(uniqueName);
+ textExplorerFile.setName(explorerFile.getName() + " (Text)");
+ textExplorerFile.setFileType(textFileType);
+
+ // Create the handler directly - BaseTextExplorerFileTypeHandler
handles VFS
+ // URIs correctly
+ TextExplorerFileTypeHandler handler =
+ new TextExplorerFileTypeHandler(hopGui, perspective,
textExplorerFile);
+
+ // Add to perspective (this will open a new tab due to unique URI
string)
+ perspective.addFile(handler);
+ }
+ } catch (Exception e) {
+ HopGui.getInstance().getLog().logError("Error opening file as text", e);
+ }
+ }
+}
diff --git
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/PdfExplorerFileType.java
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/PdfExplorerFileType.java
new file mode 100644
index 0000000000..cda98ad52d
--- /dev/null
+++
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/PdfExplorerFileType.java
@@ -0,0 +1,60 @@
+/*
+ * 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.pipeline.transforms.types;
+
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.HopFileTypePlugin;
+import org.apache.hop.ui.hopgui.file.IHopFileType;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+import org.apache.hop.ui.hopgui.file.empty.EmptyHopFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerFile;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
+import
org.apache.hop.ui.hopgui.perspective.explorer.file.capabilities.FileTypeCapabilities;
+import
org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileType;
+
+@HopFileTypePlugin(
+ id = "PdfExplorerFileType",
+ name = "PDF File Type",
+ description = "PDF file handling in the explorer perspective",
+ image = "ui/images/pdf.svg")
+public class PdfExplorerFileType extends
BaseExplorerFileType<PdfExplorerFileTypeHandler> {
+
+ public PdfExplorerFileType() {
+ super(
+ "PDF File",
+ ".pdf",
+ new String[] {"*.pdf"},
+ new String[] {"PDF files"},
+ FileTypeCapabilities.getCapabilities(
+ IHopFileType.CAPABILITY_CLOSE,
IHopFileType.CAPABILITY_FILE_HISTORY));
+ }
+
+ @Override
+ public PdfExplorerFileTypeHandler createFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file) {
+ return new PdfExplorerFileTypeHandler(hopGui, perspective, file);
+ }
+
+ @Override
+ public IHopFileTypeHandler newFile(HopGui hopGui, IVariables
parentVariableSpace)
+ throws HopException {
+ return new EmptyHopFileTypeHandler();
+ }
+}
diff --git
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/PdfExplorerFileTypeHandler.java
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/PdfExplorerFileTypeHandler.java
new file mode 100644
index 0000000000..e55ce630b8
--- /dev/null
+++
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/PdfExplorerFileTypeHandler.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.pipeline.transforms.types;
+
+import org.apache.hop.core.Const;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.core.vfs.HopVfs;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerFile;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
+import
org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileTypeHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+
+/** This handles a PDF file in the file explorer perspective: open, view, ...
*/
+public class PdfExplorerFileTypeHandler extends BaseExplorerFileTypeHandler {
+
+ private Browser wBrowser;
+
+ public PdfExplorerFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile
explorerFile) {
+ super(hopGui, perspective, explorerFile);
+ }
+
+ @Override
+ public void renderFile(Composite composite) {
+ // Render the file by showing the PDF content in a browser widget
+ // The browser widget can display PDFs using the browser's built-in PDF
viewer
+ //
+ wBrowser = new Browser(composite, SWT.NONE);
+ PropsUi.setLook(wBrowser);
+ FormData fdBrowser = new FormData();
+ fdBrowser.left = new FormAttachment(0, 0);
+ fdBrowser.right = new FormAttachment(100, 0);
+ fdBrowser.top = new FormAttachment(0, 0);
+ fdBrowser.bottom = new FormAttachment(100, 0);
+ wBrowser.setLayoutData(fdBrowser);
+
+ reload();
+ }
+
+ @Override
+ public void reload() {
+ try {
+ // Get the file URL and load it in the browser
+ // The browser widget will use its built-in PDF viewer to display the PDF
+ //
+ String filename = explorerFile.getFilename();
+
+ // Check if file exists
+ if (!HopVfs.fileExists(filename)) {
+ showError("File not found: " + filename);
+ return;
+ }
+
+ // Convert the filename to a file URL
+ // For local files, we need to use the file:// protocol
+ String fileUrl = HopVfs.getFileObject(filename).getURL().toString();
+
+ // Set the URL in the browser widget
+ wBrowser.setUrl(fileUrl);
+
+ // Clear any change flags since we just reloaded
+ clearChanged();
+ } catch (Exception e) {
+ LogChannel.UI.logError("Error loading PDF file '" +
explorerFile.getFilename() + "'", e);
+ showError("Error loading PDF file: " + Const.NVL(e.getMessage(),
"Unknown error"));
+ }
+ }
+
+ /**
+ * Show an error message in the browser widget
+ *
+ * @param message The error message to display
+ */
+ private void showError(String message) {
+ wBrowser.setText(
+ "<html><body><h1>Error loading PDF file</h1><p>" + message +
"</p></body></html>");
+ }
+
+ @Override
+ public void selectAll() {
+ // Browser widget doesn't support selectAll for PDF content
+ // For now, do nothing
+ }
+
+ @Override
+ public void unselectAll() {
+ // Browser widget doesn't support unselectAll for PDF content
+ // For now, do nothing
+ }
+
+ @Override
+ public void copySelectedToClipboard() {
+ // Browser widget doesn't directly support copy to clipboard for PDF
content
+ // For now, do nothing
+ }
+}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopPipelineFileType.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopPipelineFileType.java
index 55713a7d72..6e126ec70a 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopPipelineFileType.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopPipelineFileType.java
@@ -119,7 +119,8 @@ public class HopPipelineFileType<T extends PipelineMeta>
extends HopFileTypeBase
filename = HopVfs.normalize(variables.resolve(filename));
// See if the same pipeline isn't already open.
- // Other file types we might allow to open more than once but not
pipelines for now.
+ // Other file types we might allow to open more than once but not
pipelines for
+ // now.
//
IHopFileTypeHandler fileTypeHandler =
HopGui.getExplorerPerspective().findFileTypeHandlerByFilename(filename);
@@ -200,7 +201,7 @@ public class HopPipelineFileType<T extends PipelineMeta>
extends HopFileTypeBase
return super.isHandledBy(filename, checkContent);
}
} catch (Exception e) {
- throw new HopException("Unable to verify file handling of file '" +
filename + "'", e);
+ return false;
}
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/config/ExplorerPerspectiveConfig.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/config/ExplorerPerspectiveConfig.java
index e6c0175105..9c7b541949 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/config/ExplorerPerspectiveConfig.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/config/ExplorerPerspectiveConfig.java
@@ -24,11 +24,13 @@ public class ExplorerPerspectiveConfig {
private String lazyLoadingDepth;
private String fileLoadingMaxSize;
private Boolean fileExplorerVisibleByDefault;
+ private Boolean openingHelpFiles;
public ExplorerPerspectiveConfig() {
this.lazyLoadingDepth = "0";
this.fileLoadingMaxSize = "16";
this.fileExplorerVisibleByDefault = true;
+ this.openingHelpFiles = false;
}
public ExplorerPerspectiveConfig(ExplorerPerspectiveConfig config) {
@@ -36,6 +38,7 @@ public class ExplorerPerspectiveConfig {
this.lazyLoadingDepth = config.lazyLoadingDepth;
this.fileLoadingMaxSize = config.fileLoadingMaxSize;
this.fileExplorerVisibleByDefault = config.fileExplorerVisibleByDefault;
+ this.openingHelpFiles = config.openingHelpFiles;
}
public String getLazyLoadingDepth() {
@@ -61,4 +64,12 @@ public class ExplorerPerspectiveConfig {
public void setFileExplorerVisibleByDefault(Boolean
fileExplorerVisibleByDefault) {
this.fileExplorerVisibleByDefault = fileExplorerVisibleByDefault;
}
+
+ public Boolean isOpeningHelpFiles() {
+ return openingHelpFiles != null ? openingHelpFiles : false;
+ }
+
+ public void setOpeningHelpFiles(Boolean openingHelpFiles) {
+ this.openingHelpFiles = openingHelpFiles;
+ }
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/config/ExplorerPerspectiveConfigPlugin.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/config/ExplorerPerspectiveConfigPlugin.java
index 831f6101b4..7df5487fc9 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/config/ExplorerPerspectiveConfigPlugin.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/config/ExplorerPerspectiveConfigPlugin.java
@@ -50,6 +50,7 @@ public class ExplorerPerspectiveConfigPlugin
private static final String WIDGET_ID_FILE_LOADING_MAX_SIZE =
"10100-file-loading-max-size";
private static final String WIDGET_ID_FILE_EXPLORER_VISIBLE_BY_DEFAULT =
"10200-file-explorer-visible-by-default";
+ private static final String WIDGET_ID_OPEN_HELP_FILES =
"10300-open-help-files";
@GuiWidgetElement(
id = WIDGET_ID_LAZY_LOADING_DEPTH,
@@ -86,6 +87,17 @@ public class ExplorerPerspectiveConfigPlugin
description = "Show the file explorer panel by default in the explorer
perspective")
private Boolean fileExplorerVisibleByDefault = true;
+ @GuiWidgetElement(
+ id = WIDGET_ID_OPEN_HELP_FILES,
+ parentId = ConfigPluginOptionsTab.GUI_WIDGETS_PARENT_ID,
+ type = GuiElementType.CHECKBOX,
+ label = "i18n::ExplorerPerspectiveConfig.OpenHelpFiles.Label",
+ toolTip = "i18n::ExplorerPerspectiveConfig.OpenHelpFiles.Tooltip")
+ @CommandLine.Option(
+ names = {"-oh", "--open-help-in-tabs"},
+ description = "Open help files in Hop GUI tabs instead of external
browser")
+ private Boolean openingHelpFiles;
+
/**
* Gets instance
*
@@ -99,6 +111,7 @@ public class ExplorerPerspectiveConfigPlugin
instance.fileLoadingMaxSize = config.getFileLoadingMaxSize();
Boolean visibleByDefault = config.getFileExplorerVisibleByDefault();
instance.fileExplorerVisibleByDefault = visibleByDefault != null ?
visibleByDefault : true;
+ instance.openingHelpFiles = config.isOpeningHelpFiles();
return instance;
}
@@ -136,6 +149,13 @@ public class ExplorerPerspectiveConfigPlugin
changed = true;
}
+ if (openingHelpFiles != null) {
+ config.setOpeningHelpFiles(openingHelpFiles);
+ log.logBasic(
+ "Explorer perspective: open help files in tabs is set to '" +
openingHelpFiles + "'");
+ changed = true;
+ }
+
// Save to file if anything changed
//
if (changed) {
@@ -181,6 +201,10 @@ public class ExplorerPerspectiveConfigPlugin
ExplorerPerspectiveConfigSingleton.getConfig()
.setFileExplorerVisibleByDefault(fileExplorerVisibleByDefault);
break;
+ case WIDGET_ID_OPEN_HELP_FILES:
+ openingHelpFiles = ((Button) control).getSelection();
+
ExplorerPerspectiveConfigSingleton.getConfig().setOpeningHelpFiles(openingHelpFiles);
+ break;
default:
break;
}
@@ -217,4 +241,12 @@ public class ExplorerPerspectiveConfigPlugin
public void setFileExplorerVisibleByDefault(Boolean
fileExplorerVisibleByDefault) {
this.fileExplorerVisibleByDefault = fileExplorerVisibleByDefault;
}
+
+ public Boolean isOpeningHelpFiles() {
+ return openingHelpFiles != null ? openingHelpFiles : false;
+ }
+
+ public void setOpeningHelpFiles(Boolean openingHelpFiles) {
+ this.openingHelpFiles = openingHelpFiles;
+ }
}
diff --git a/ui/src/main/java/org/apache/hop/ui/util/HelpUtils.java
b/ui/src/main/java/org/apache/hop/ui/util/HelpUtils.java
index d5dd2327ad..45ecae820c 100644
--- a/ui/src/main/java/org/apache/hop/ui/util/HelpUtils.java
+++ b/ui/src/main/java/org/apache/hop/ui/util/HelpUtils.java
@@ -23,6 +23,7 @@ import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.apache.hop.core.HopEnvironment;
import org.apache.hop.core.database.DatabasePluginType;
+import org.apache.hop.core.exception.HopException;
import org.apache.hop.core.plugins.ActionPluginType;
import org.apache.hop.core.plugins.IPlugin;
import org.apache.hop.core.plugins.TransformPluginType;
@@ -33,6 +34,10 @@ import org.apache.hop.ui.core.PropsUi;
import org.apache.hop.ui.core.dialog.ErrorDialog;
import org.apache.hop.ui.core.dialog.MessageBox;
import org.apache.hop.ui.core.gui.GuiResource;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.HopFileTypeRegistry;
+import org.apache.hop.ui.hopgui.file.IHopFileType;
+import
org.apache.hop.ui.hopgui.perspective.explorer.config.ExplorerPerspectiveConfigSingleton;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
@@ -91,7 +96,11 @@ public class HelpUtils {
try {
String originalUrl = getDocUrl(plugin.getDocumentationUrl());
String trackedUrl = appendUtmParameters(originalUrl);
- EnvironmentUtils.getInstance().openUrl(trackedUrl);
+ if
(ExplorerPerspectiveConfigSingleton.getConfig().isOpeningHelpFiles()) {
+ openHelpInTab(trackedUrl);
+ } else {
+ EnvironmentUtils.getInstance().openUrl(trackedUrl);
+ }
} catch (Exception ex) {
new ErrorDialog(shell, "Error", "Error opening URL", ex);
}
@@ -143,4 +152,17 @@ public class HelpUtils {
return URLEncoder.encode(field, StandardCharsets.UTF_8);
}
+
+ private static void openHelpInTab(String url) throws HopException {
+ HopGui hopGui = HopGui.getInstance();
+ if (hopGui != null) {
+ IHopFileType htmlFileType =
HopFileTypeRegistry.getInstance().findHopFileType("help.html");
+ if (htmlFileType != null) {
+ htmlFileType.openFile(hopGui, url, hopGui.getVariables());
+ return;
+ }
+ }
+ // Fallback
+ EnvironmentUtils.getInstance().openUrl(url);
+ }
}
diff --git
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/config/messages/messages_en_US.properties
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/config/messages/messages_en_US.properties
index 4afe25f5f6..7938d11c8f 100644
---
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/config/messages/messages_en_US.properties
+++
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/config/messages/messages_en_US.properties
@@ -21,3 +21,6 @@ ExplorerPerspectiveConfig.LazyLoading.Label=The initial depth
to load not lazily
ExplorerPerspectiveConfig.LazyLoading.Tooltip=The initial depth to load not
lazily
ExplorerPerspectiveConfig.FileExplorerVisible.Label=Show file explorer panel
by default
ExplorerPerspectiveConfig.FileExplorerVisible.Tooltip=When enabled, the file
explorer panel (project tree) is shown by default when opening the explorer
perspective
+
+ExplorerPerspectiveConfig.OpenHelpFiles.Label=Open help files in Hop GUI tabs
instead of external browser
+ExplorerPerspectiveConfig.OpenHelpFiles.Tooltip=When checked, help links will
open as a new tab within the Hop GUI using the internal HTML viewer. Unchecked
will open the system default browser.
diff --git
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/messages/messages_en_US.properties
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/messages/messages_en_US.properties
index 8782595422..f0af81d93a 100644
---
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/messages/messages_en_US.properties
+++
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/explorer/messages/messages_en_US.properties
@@ -53,4 +53,5 @@ ExplorerPerspective.ToolbarElement.Refresh.Tooltip=Refresh
ExplorerPerspective.ToolbarElement.Rename.Tooltip=Rename the selected file
ExplorerPerspective.ToolbarElement.ExpandAll.Tooltip=Expand all folders
ExplorerPerspective.ToolbarElement.CollapseAll.Tooltip=Collapse all folders
-ExplorerPerspective.ToolbarElement.SelectOpenedFile.Tooltip=Select opened file
\ No newline at end of file
+ExplorerPerspective.ToolbarElement.SelectOpenedFile.Tooltip=Select opened file
+ExplorerPerspective.ToolbarElement.OpenAsText.Label=Open as text
diff --git a/ui/src/main/resources/ui/images/html.svg
b/ui/src/main/resources/ui/images/html.svg
new file mode 100644
index 0000000000..80db07309f
--- /dev/null
+++ b/ui/src/main/resources/ui/images/html.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="42" height="42" viewBox="0 0 42
42">
+ <!-- Document background -->
+ <path fill="#E67E22" d="M6.608,2.564v36.867H34.49V8.996h-6.729V2.564"/>
+ <!-- Document outline and fold -->
+ <path fill="#D35400"
d="M34.477,6.429h-4.029V2.583L27.745,0H3.921v42h33.257V9.008L34.477,6.429z
M12.097,2.565h15.665v6.432h6.729v30.436H6.608V2.565h3.591"/>
+ <!-- HTML text -->
+ <text x="21" y="26" font-family="Arial, sans-serif" font-size="7"
font-weight="bold" fill="#FFFFFF" text-anchor="middle">HTML</text>
+</svg>
diff --git a/ui/src/main/resources/ui/images/pdf.svg
b/ui/src/main/resources/ui/images/pdf.svg
new file mode 100644
index 0000000000..688ea3333b
--- /dev/null
+++ b/ui/src/main/resources/ui/images/pdf.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="42" height="42" viewBox="0 0 42
42">
+ <!-- Document background -->
+ <path fill="#E74C3C" d="M6.608,2.564v36.867H34.49V8.996h-6.729V2.564"/>
+ <!-- Document outline and fold -->
+ <path fill="#C0392B"
d="M34.477,6.429h-4.029V2.583L27.745,0H3.921v42h33.257V9.008L34.477,6.429z
M12.097,2.565h15.665v6.432h6.729v30.436H6.608V2.565h3.591"/>
+ <!-- PDF text -->
+ <text x="21" y="28" font-family="Arial, sans-serif" font-size="10"
font-weight="bold" fill="#FFFFFF" text-anchor="middle">PDF</text>
+</svg>