You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hop.apache.org by ha...@apache.org on 2021/03/02 19:51:11 UTC
[incubator-hop] branch master updated: HOP-2575 : Create a file
explorer perspective
This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-hop.git
The following commit(s) were added to refs/heads/master by this push:
new 6351158 HOP-2575 : Create a file explorer perspective
new f906040 Merge pull request #660 from mattcasters/master
6351158 is described below
commit 6351158cd4ea91176716db31c3d5b14dc99c100e
Author: Matt Casters <ma...@gmail.com>
AuthorDate: Tue Mar 2 18:15:43 2021 +0100
HOP-2575 : Create a file explorer perspective
---
.../java/org/apache/hop/core/svg/SvgCache.java | 7 +-
.../hop/projects/xp/ExplorerPerspectiveRoot.java | 58 ++
.../transforms/types/JsonExplorerFileType.java | 74 ++
.../types/JsonExplorerFileTypeHandler.java | 114 +++
.../transforms/json/src/main/resources/json.svg | 17 +
.../sasinput/types/SasExplorerFileType.java | 70 ++
.../sasinput/types/SasExplorerFileTypeHandler.java | 100 +++
.../src/main/resources/{SASInput.svg => SAS.svg} | 2 +-
.../sasinput/src/main/resources/SASInput.svg | 1 +
.../transforms/types/CsvExplorerFileType.java | 68 ++
.../types/CsvExplorerFileTypeHandler.java | 78 ++
.../transforms/types/TextExplorerFileType.java | 68 ++
.../types/TextExplorerFileTypeHandler.java | 80 ++
.../textfile/src/main/resources/textfile.svg | 15 +
.../transforms/xml/types/XmlExplorerFileType.java | 68 ++
.../xml/types/XmlExplorerFileTypeHandler.java | 80 ++
.../org/apache/hop/core/SwtUniversalImageSvg.java | 6 +-
.../hop/ui/core/metadata/MetadataFileType.java | 4 +
.../ui/core/metadata/MetadataFileTypeHandler.java | 4 +-
.../apache/hop/ui/core/vfs/HopVfsFileDialog.java | 2 +-
.../main/java/org/apache/hop/ui/hopgui/HopGui.java | 2 +-
.../apache/hop/ui/hopgui/HopGuiExtensionPoint.java | 3 +
.../ui/hopgui/delegates/HopGuiFileDelegate.java | 8 +-
.../apache/hop/ui/hopgui/file/HopFileTypeBase.java | 13 +-
.../apache/hop/ui/hopgui/file/IHopFileType.java | 59 +-
.../hop/ui/hopgui/file/empty/EmptyFileType.java | 7 +-
.../hopgui/file/pipeline/HopPipelineFileType.java | 6 +-
.../hopgui/file/workflow/HopWorkflowFileType.java | 6 +-
.../hopgui/perspective/HopPerspectiveManager.java | 4 +-
.../hopgui/perspective/explorer/ExplorerFile.java | 198 +++++
.../perspective/explorer/ExplorerPerspective.java | 812 +++++++++++++++++++++
.../explorer/IExplorerFileContentCallback.java | 24 +
.../explorer/IExplorerFilePaintListener.java | 31 +
.../explorer/file/ExplorerFileType.java} | 23 +-
.../explorer/file/ExplorerFileTypeHandler.java | 156 ++++
.../perspective/explorer/file/FileDetails.java | 63 ++
.../explorer/file/IExplorerFileType.java | 37 +
.../explorer/file/IExplorerFileTypeHandler.java | 33 +
.../file/capabilities/FileTypeCapabilities.java | 31 +
.../explorer/file/types/FolderFileType.java | 116 +++
.../explorer/file/types/GenericFileType.java | 111 +++
.../file/types/base/BaseExplorerFileType.java | 188 +++++
.../types/base/BaseExplorerFileTypeHandler.java | 246 +++++++
.../file/types/log/LogExplorerFileType.java | 69 ++
.../file/types/log/LogExplorerFileTypeHandler.java | 83 +++
.../file/types/svg/SvgExplorerFileType.java | 71 ++
.../file/types/svg/SvgExplorerFileTypeHandler.java | 92 +++
47 files changed, 3347 insertions(+), 61 deletions(-)
diff --git a/core/src/main/java/org/apache/hop/core/svg/SvgCache.java b/core/src/main/java/org/apache/hop/core/svg/SvgCache.java
index bd3a82b..d13e501 100644
--- a/core/src/main/java/org/apache/hop/core/svg/SvgCache.java
+++ b/core/src/main/java/org/apache/hop/core/svg/SvgCache.java
@@ -31,6 +31,7 @@ import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGSVGElement;
import java.awt.geom.Rectangle2D;
+import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@@ -71,9 +72,11 @@ public class SvgCache {
String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory( parser );
InputStream svgStream = svgFile.getClassLoader().getResourceAsStream( svgFile.getFilename() );
-
if ( svgStream == null ) {
- throw new HopException( "Unable to find file '" + svgFile.getFilename() + "'" );
+
+ // Retry on the regular filesystem...
+ //
+ svgStream = new FileInputStream( svgFile.getFilename() );
}
SVGDocument svgDocument = factory.createSVGDocument( svgFile.getFilename(), svgStream );
SVGSVGElement elSVG = svgDocument.getRootElement();
diff --git a/plugins/misc/projects/src/main/java/org/apache/hop/projects/xp/ExplorerPerspectiveRoot.java b/plugins/misc/projects/src/main/java/org/apache/hop/projects/xp/ExplorerPerspectiveRoot.java
new file mode 100644
index 0000000..c55c5cf
--- /dev/null
+++ b/plugins/misc/projects/src/main/java/org/apache/hop/projects/xp/ExplorerPerspectiveRoot.java
@@ -0,0 +1,58 @@
+/*
+ * 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.projects.xp;
+
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.extension.ExtensionPoint;
+import org.apache.hop.core.extension.IExtensionPoint;
+import org.apache.hop.core.logging.ILogChannel;
+import org.apache.hop.core.util.StringUtil;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.projects.config.ProjectsConfig;
+import org.apache.hop.projects.config.ProjectsConfigSingleton;
+import org.apache.hop.projects.project.ProjectConfig;
+import org.apache.hop.ui.core.gui.HopNamespace;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
+
+@ExtensionPoint(
+ id = "ExplorerPerspectiveRoot",
+ description = "Set the root folder and name of the current project in the explorer perspective",
+ extensionPointId = "HopGuiDetermineExplorerRoot")
+public class ExplorerPerspectiveRoot
+ implements IExtensionPoint<ExplorerPerspective.DetermineRootFolderExtension> {
+ @Override
+ public void callExtensionPoint(
+ ILogChannel log, IVariables variables, ExplorerPerspective.DetermineRootFolderExtension ext)
+ throws HopException {
+
+ // Get the current project...
+ //
+ String projectName = HopNamespace.getNamespace();
+ if ( StringUtil.isEmpty(projectName)) {
+ return;
+ }
+ ProjectsConfig config = ProjectsConfigSingleton.getConfig();
+ ProjectConfig projectConfig = config.findProjectConfig( projectName );
+ if (projectConfig==null) {
+ return;
+ }
+ ext.rootFolder = projectConfig.getProjectHome();
+ ext.rootName = projectName;
+ }
+}
diff --git a/plugins/transforms/json/src/main/java/org/apache/hop/pipeline/transforms/types/JsonExplorerFileType.java b/plugins/transforms/json/src/main/java/org/apache/hop/pipeline/transforms/types/JsonExplorerFileType.java
new file mode 100644
index 0000000..cddb7a8
--- /dev/null
+++ b/plugins/transforms/json/src/main/java/org/apache/hop/pipeline/transforms/types/JsonExplorerFileType.java
@@ -0,0 +1,74 @@
+/*
+ * 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.Props;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.ui.core.PropsUi;
+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.IExplorerFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.capabilities.FileTypeCapabilities;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileType;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+@HopFileTypePlugin(
+ id = "JsonExplorerFileType",
+ name = "JSON File Type",
+ description = "JSON file handling in the explorer perspective",
+ image = "json.svg")
+public class JsonExplorerFileType extends BaseExplorerFileType<JsonExplorerFileTypeHandler>
+ implements IExplorerFileType<JsonExplorerFileTypeHandler> {
+
+ public JsonExplorerFileType() {
+ super(
+ "JSON File",
+ ".json",
+ new String[] {"*.json"},
+ new String[] {"JSON files"},
+ FileTypeCapabilities.getCapabilities( IHopFileType.CAPABILITY_SAVE ));
+ }
+
+ @Override
+ public JsonExplorerFileTypeHandler createFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file) {
+ return new JsonExplorerFileTypeHandler(hopGui, perspective, file);
+ }
+
+ @Override
+ public IHopFileTypeHandler newFile(HopGui hopGui, IVariables parentVariableSpace)
+ throws HopException {
+ return new EmptyHopFileTypeHandler();
+ }
+}
diff --git a/plugins/transforms/json/src/main/java/org/apache/hop/pipeline/transforms/types/JsonExplorerFileTypeHandler.java b/plugins/transforms/json/src/main/java/org/apache/hop/pipeline/transforms/types/JsonExplorerFileTypeHandler.java
new file mode 100644
index 0000000..6ed4da4
--- /dev/null
+++ b/plugins/transforms/json/src/main/java/org/apache/hop/pipeline/transforms/types/JsonExplorerFileTypeHandler.java
@@ -0,0 +1,114 @@
+/*
+ * 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.Props;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+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.IExplorerFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileTypeHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+/** How do we handle a JSON file in file explorer perspective? */
+public class JsonExplorerFileTypeHandler extends BaseExplorerFileTypeHandler implements IExplorerFileTypeHandler {
+
+ private Text wText;
+
+ public JsonExplorerFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile explorerFile) {
+ super(hopGui, perspective, explorerFile);
+ }
+
+
+ @Override
+ public void renderFile(Composite composite) {
+ // Render the file by simply showing the file content as a text widget...
+ //
+ wText = new Text(composite, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ PropsUi.getInstance().setLook(wText, Props.WIDGET_STYLE_FIXED);
+ FormData fdText = new FormData();
+ fdText.left = new FormAttachment(0, 0);
+ fdText.right = new FormAttachment(100, 0);
+ fdText.top = new FormAttachment(0, 0);
+ fdText.bottom = new FormAttachment(100, 0);
+ wText.setLayoutData(fdText);
+
+ // TODO: add bottom section to show status, size, changed dates, cursor position...
+ // TODO: options for validation, pretty print, ...
+ // TODO: options for reading the file with a JSON Input transform
+ // TODO: option to discard changes (reload from disk)
+ // TODO: find in file feature, hook it up to the project find function
+ //
+
+ // Load the content of the JSON file...
+ //
+ File file = new File(explorerFile.getFilename());
+ if (file.exists()) {
+ try {
+ String contents = new String( Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
+ wText.setText(contents);
+ } catch (Exception e) {
+ LogChannel.UI.logError(
+ "Error reading contents of file '" + explorerFile.getFilename() + "'", e);
+ }
+ }
+
+ // If the widget changes after this it's been changed by the user
+ //
+ wText.addModifyListener( e->explorerFile.setChanged() );
+ }
+
+
+ @Override
+ public void save() throws HopException {
+
+ try {
+ // Save the current explorer file ....
+ //
+ String filename = explorerFile.getFilename();
+
+ // Save the file...
+ //
+ try( OutputStream outputStream = new FileOutputStream( filename ) ) {
+ outputStream.write(wText.getText().getBytes( StandardCharsets.UTF_8 ));
+ outputStream.flush();
+ }
+
+ explorerFile.clearChanged();
+
+ } catch(Exception e) {
+ throw new HopException("Unable to save JSON file '"+explorerFile.getFilename()+"'", e);
+ }
+ }
+}
diff --git a/plugins/transforms/json/src/main/resources/json.svg b/plugins/transforms/json/src/main/resources/json.svg
new file mode 100644
index 0000000..717bdf4
--- /dev/null
+++ b/plugins/transforms/json/src/main/resources/json.svg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 14.464 14.466"
+ height="14.466"
+ width="14.464"
+ y="0px"
+ x="0px"
+ version="1.1">
+ <path
+ d="m 8.105,0.196 c 2.116,0.685 3.317,2.208 3.799,3.902 0.019,0.067 0.032,0.135 0.049,0.203 0.025,0.101 0.053,0.202 0.073,0.304 0.697,3.478 -1.441,7.386 -4.787,6.223 0,0 0.025,-0.013 0.034,-0.017 -10e-4,0 -0.002,0 -0.003,-10e-4 l -0.039,0.019 c 0,0 -2.143,-0.949 -2.143,-3.734 0,-2.636 2.143,-3.456 2.143,-3.456 0,0 0.042,0.016 0.113,0.05 0,0 -0.002,-10e-4 -0.002,-10e-4 C 7.314,3.673 7.292,3.662 7.275,3.653 7.261,3.647 7.232,3.632 7.232,3.632 2.69,2.717 1.198,9.593 4.302,12.89 c 0.735, [...]
+ style="fill:#3d6480" />
+ <path
+ d="M 7.232,14.465 C 5.993,14.229 5.024,13.655 4.302,12.889 1.198,9.592 2.689,2.716 7.232,3.631 c 0,0 0.029,0.015 0.043,0.021 0.018,0.009 0.039,0.02 0.067,0.035 0.001,0 0.002,0.001 0.002,0.001 0.436,0.231 2.038,1.233 2.038,3.526 0,2.552 -1.929,3.512 -2.109,3.596 -0.009,0.004 -0.034,0.017 -0.034,0.017 3.346,1.163 5.484,-2.745 4.787,-6.223 C 12.005,4.502 11.978,4.401 11.953,4.3 11.936,4.232 11.923,4.164 11.904,4.097 11.42,2.402 10.218,0.879 8.105,0.195 8.09,0.19 8.077,0.184 8.062,0.179 [...]
+ style="fill:#9fb2c0" />
+</svg>
diff --git a/plugins/transforms/sasinput/src/main/java/org/apache/hop/pipeline/transforms/sasinput/types/SasExplorerFileType.java b/plugins/transforms/sasinput/src/main/java/org/apache/hop/pipeline/transforms/sasinput/types/SasExplorerFileType.java
new file mode 100644
index 0000000..46a357f
--- /dev/null
+++ b/plugins/transforms/sasinput/src/main/java/org/apache/hop/pipeline/transforms/sasinput/types/SasExplorerFileType.java
@@ -0,0 +1,70 @@
+/*
+ * 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.sasinput.types;
+
+import com.epam.parso.Column;
+import com.epam.parso.ColumnFormat;
+import com.epam.parso.impl.SasFileReaderImpl;
+import org.apache.hop.core.Const;
+import org.apache.hop.core.Props;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.core.vfs.HopVfs;
+import org.apache.hop.pipeline.transforms.sasinput.SasUtil;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.HopFileTypePlugin;
+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.IExplorerFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileType;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Properties;
+
+@HopFileTypePlugin(
+ id = "SasExplorerFileType",
+ name = "SAS File Type",
+ description = "SAS file handling in the explorer perspective",
+ image = "SAS.svg")
+public class SasExplorerFileType extends BaseExplorerFileType<SasExplorerFileTypeHandler>
+ implements IExplorerFileType<SasExplorerFileTypeHandler> {
+
+ public SasExplorerFileType() {
+ super( "SAS file", ".sas7bdat", new String[] {"*.sas7bdat"}, new String[] {"SAS 7 BDAT files"}, new Properties() );
+ }
+
+ @Override
+ public IHopFileTypeHandler newFile(HopGui hopGui, IVariables parentVariableSpace)
+ throws HopException {
+ return new EmptyHopFileTypeHandler();
+ }
+
+ @Override public SasExplorerFileTypeHandler createFileTypeHandler( HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file ) {
+ return new SasExplorerFileTypeHandler(hopGui, perspective, file);
+ }
+}
diff --git a/plugins/transforms/sasinput/src/main/java/org/apache/hop/pipeline/transforms/sasinput/types/SasExplorerFileTypeHandler.java b/plugins/transforms/sasinput/src/main/java/org/apache/hop/pipeline/transforms/sasinput/types/SasExplorerFileTypeHandler.java
new file mode 100644
index 0000000..789b1de
--- /dev/null
+++ b/plugins/transforms/sasinput/src/main/java/org/apache/hop/pipeline/transforms/sasinput/types/SasExplorerFileTypeHandler.java
@@ -0,0 +1,100 @@
+/*
+ * 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.sasinput.types;
+
+import com.epam.parso.Column;
+import com.epam.parso.ColumnFormat;
+import com.epam.parso.impl.SasFileReaderImpl;
+import org.apache.hop.core.Const;
+import org.apache.hop.core.Props;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.vfs.HopVfs;
+import org.apache.hop.pipeline.transforms.sasinput.SasUtil;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+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.IExplorerFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileTypeHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.InputStream;
+import java.util.List;
+
+/**
+ * How do we handle an SVG file in file explorer perspective?
+ */
+public class SasExplorerFileTypeHandler extends BaseExplorerFileTypeHandler implements IExplorerFileTypeHandler {
+
+ public SasExplorerFileTypeHandler( HopGui hopGui, ExplorerPerspective perspective, ExplorerFile explorerFile ) {
+ super( hopGui, perspective, explorerFile );
+ }
+
+ @Override
+ public void renderFile(Composite composite) {
+ // Render the file by simply showing the filename ...
+ // TODO: create a TableView based in the file content & load it up...
+ //
+ //
+ Text wText = new Text(composite, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ PropsUi.getInstance().setLook(wText, Props.WIDGET_STYLE_FIXED);
+ wText.setEditable( false );
+ FormData fdText = new FormData();
+ fdText.left = new FormAttachment(0, 0);
+ fdText.right = new FormAttachment(100, 0);
+ fdText.top = new FormAttachment(0, 0);
+ fdText.bottom = new FormAttachment(100, 0);
+ wText.setLayoutData(fdText);
+
+ String message = explorerFile.getFilename()+ Const.CR;
+ message+=Const.CR;
+
+ try {
+ try ( InputStream inputStream = HopVfs.getInputStream(explorerFile.getFilename())) {
+ SasFileReaderImpl sasFileReader = new SasFileReaderImpl(inputStream);
+
+ List<Column> columns = sasFileReader.getColumns();
+ for (int c = 0; c < columns.size(); c++) {
+ Column column = columns.get(c);
+ ColumnFormat format = column.getFormat();
+
+ int length = format.getWidth()==0 ? -1 : format.getWidth();
+ int precision = format.getPrecision()==0 ? -1 : format.getWidth();
+
+ message+="Column "+(c+1)+Const.CR;
+ message+=" Name : "+Const.NVL(column.getName(), "")+Const.CR;
+ message+=" Type : "+ SasUtil.getHopDataTypeDesc(column.getType())+Const.CR;
+ message+=" Length : "+(length<0 ? "" : Integer.toString(length))+Const.CR;
+ message+=" Precision : "+(precision<0 ? "" : Integer.toString( precision ))+Const.CR;
+ }
+ } catch (Exception e) {
+ throw new HopException("Error reading from file: " + explorerFile.getFilename());
+ }
+ } catch(Exception e) {
+ message+= Const.CR+Const.getSimpleStackTrace( e );
+ }
+ wText.setText( message );
+ }
+
+}
diff --git a/plugins/transforms/sasinput/src/main/resources/SASInput.svg b/plugins/transforms/sasinput/src/main/resources/SAS.svg
similarity index 90%
copy from plugins/transforms/sasinput/src/main/resources/SASInput.svg
copy to plugins/transforms/sasinput/src/main/resources/SAS.svg
index 302f32b..7c42634 100644
--- a/plugins/transforms/sasinput/src/main/resources/SASInput.svg
+++ b/plugins/transforms/sasinput/src/main/resources/SAS.svg
@@ -6,11 +6,11 @@
y="0px"
viewBox="-9 -9 42 42"
enable-background="new -9 -9 42 42"
+ width="42px" height="42px"
>
<polygon fill="#0e3a5a" points="0.9,23.1 0.9,0.9 23.2,0.9 23.2,13.9 24.9,12.2 24.9,-0.9 -0.8,-0.9 -0.8,24.9 11.8,24.9
13.6,23.1"/>
<polygon fill="#c9e8fb" points="0.9,0.9 0.9,23.1 13.6,23.1 23.2,13.9 23.2,0.9"/>
- <polygon fill="#0e3a5a" points="28.1,23.6 28.1,26.7 22.9,21.5 21.5,22.8 26.8,28.1 23.6,28.1 23.6,30 30,30 30,23.6"/>
<path fill="#0e3a5a" d="M6.5,14.9c-0.6,0-1.4-0.1-2-0.4l0.1-0.7c0.6,0.2,1.2,0.3,1.9,0.3c1.1,0,1.3-0.3,1.3-1c0-0.9,0-1-1.4-1.3
c-1.6-0.4-1.8-0.7-1.8-2C4.6,8.6,5.1,8,6.7,8C7.3,8,8,8.1,8.5,8.2L8.4,9C7.9,8.8,7.3,8.8,6.7,8.8c-1.1,0-1.3,0.2-1.3,1
c0,0.9,0,1,1.3,1.3c1.8,0.4,1.9,0.7,1.9,2C8.6,14.2,8.3,14.9,6.5,14.9z"/>
diff --git a/plugins/transforms/sasinput/src/main/resources/SASInput.svg b/plugins/transforms/sasinput/src/main/resources/SASInput.svg
index 302f32b..3d6d052 100644
--- a/plugins/transforms/sasinput/src/main/resources/SASInput.svg
+++ b/plugins/transforms/sasinput/src/main/resources/SASInput.svg
@@ -6,6 +6,7 @@
y="0px"
viewBox="-9 -9 42 42"
enable-background="new -9 -9 42 42"
+ width="42px" height="42px"
>
<polygon fill="#0e3a5a" points="0.9,23.1 0.9,0.9 23.2,0.9 23.2,13.9 24.9,12.2 24.9,-0.9 -0.8,-0.9 -0.8,24.9 11.8,24.9
13.6,23.1"/>
diff --git a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/CsvExplorerFileType.java b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/CsvExplorerFileType.java
new file mode 100644
index 0000000..fba8b5a
--- /dev/null
+++ b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/CsvExplorerFileType.java
@@ -0,0 +1,68 @@
+/*
+ * 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.Props;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.HopFileTypePlugin;
+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.IExplorerFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileType;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.Properties;
+
+@HopFileTypePlugin(
+ id = "CsvExplorerFileType",
+ name = "JSON File Type",
+ description = "JSON file handling in the explorer perspective",
+ image = "textfile.svg")
+public class CsvExplorerFileType extends BaseExplorerFileType<TextExplorerFileTypeHandler>
+ implements IExplorerFileType<TextExplorerFileTypeHandler> {
+
+ public CsvExplorerFileType() {
+ super("CSV File", ".csv", new String[] {"*.csv"}, new String[] {"CSV files"}, new Properties());
+ }
+
+ @Override
+ public TextExplorerFileTypeHandler createFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file) {
+ return new TextExplorerFileTypeHandler(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/CsvExplorerFileTypeHandler.java b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/CsvExplorerFileTypeHandler.java
new file mode 100644
index 0000000..26d7761
--- /dev/null
+++ b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/CsvExplorerFileTypeHandler.java
@@ -0,0 +1,78 @@
+/*
+ * 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.Props;
+import org.apache.hop.core.logging.LogChannel;
+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.IExplorerFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileTypeHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+/** How do we handle an SVG file in file explorer perspective? */
+public class CsvExplorerFileTypeHandler extends BaseExplorerFileTypeHandler
+ implements IExplorerFileTypeHandler {
+
+ public CsvExplorerFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile explorerFile) {
+ super(hopGui, perspective, explorerFile);
+ }
+
+ @Override
+ public void renderFile(Composite composite) {
+ // Render the file by simply showing the file content as a text widget...
+ //
+ Text wText = new Text(composite, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ PropsUi.getInstance().setLook(wText, Props.WIDGET_STYLE_FIXED);
+ wText.setEditable(false);
+ FormData fdText = new FormData();
+ fdText.left = new FormAttachment(0, 0);
+ fdText.right = new FormAttachment(100, 0);
+ fdText.top = new FormAttachment(0, 0);
+ fdText.bottom = new FormAttachment(100, 0);
+ wText.setLayoutData(fdText);
+
+ // TODO: add bottom section to show status, size, cursor position...
+ //
+
+ // Load the content of the JSON file...
+ //
+ File file = new File(explorerFile.getFilename());
+ if (file.exists()) {
+ try {
+ String contents = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
+ wText.setText(contents);
+ } catch (Exception e) {
+ LogChannel.UI.logError(
+ "Error reading contents of file '" + explorerFile.getFilename() + "'", e);
+ }
+ }
+ }
+}
diff --git a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/TextExplorerFileType.java b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/TextExplorerFileType.java
new file mode 100644
index 0000000..abe2e54
--- /dev/null
+++ b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/TextExplorerFileType.java
@@ -0,0 +1,68 @@
+/*
+ * 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.Props;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.HopFileTypePlugin;
+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.IExplorerFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileType;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.Properties;
+
+@HopFileTypePlugin(
+ id = "TextExplorerFileType",
+ name = "TXT File Type",
+ description = "Text file handling in the explorer perspective",
+ image = "textfile.svg")
+public class TextExplorerFileType extends BaseExplorerFileType<TextExplorerFileTypeHandler>
+ implements IExplorerFileType<TextExplorerFileTypeHandler> {
+
+ public TextExplorerFileType() {
+ super("TXT File", ".txt", new String[] {"*.txt"}, new String[] {"TXT files"}, new Properties());
+ }
+
+ @Override
+ public TextExplorerFileTypeHandler createFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file) {
+ return new TextExplorerFileTypeHandler(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/TextExplorerFileTypeHandler.java b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/TextExplorerFileTypeHandler.java
new file mode 100644
index 0000000..a2d1820
--- /dev/null
+++ b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/types/TextExplorerFileTypeHandler.java
@@ -0,0 +1,80 @@
+/*
+ * 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.Props;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+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.IExplorerFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileTypeHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+/**
+ * How do we handle an SVG file in file explorer perspective?
+ */
+public class TextExplorerFileTypeHandler extends BaseExplorerFileTypeHandler implements IExplorerFileTypeHandler {
+
+ public TextExplorerFileTypeHandler( HopGui hopGui, ExplorerPerspective perspective, ExplorerFile explorerFile ) {
+ super( hopGui, perspective, explorerFile );
+ }
+
+ @Override
+ public void renderFile(Composite composite) {
+ // Render the file by simply showing the TXT content as a text widget...
+ //
+ Text wText = new Text(composite, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ PropsUi.getInstance().setLook(wText, Props.WIDGET_STYLE_FIXED);
+ wText.setEditable( false );
+ FormData fdText = new FormData();
+ fdText.left = new FormAttachment(0, 0);
+ fdText.right = new FormAttachment(100, 0);
+ fdText.top = new FormAttachment(0, 0);
+ fdText.bottom = new FormAttachment(100, 0);
+ wText.setLayoutData(fdText);
+
+ // TODO: add bottom section to show status, size, cursor position...
+ //
+
+ // Load the content of the JSON file...
+ //
+ File file = new File(explorerFile.getFilename());
+ if (file.exists()) {
+ try {
+ String contents = new String( Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
+ wText.setText(contents);
+ } catch (Exception e) {
+ LogChannel.UI.logError(
+ "Error reading contents of file '" + explorerFile.getFilename() + "'", e);
+ }
+ }
+ }
+
+}
diff --git a/plugins/transforms/textfile/src/main/resources/textfile.svg b/plugins/transforms/textfile/src/main/resources/textfile.svg
new file mode 100644
index 0000000..c261b1a
--- /dev/null
+++ b/plugins/transforms/textfile/src/main/resources/textfile.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
+ width="42px" height="42px" viewBox="0 0 42 42" enable-background="new 0 0 42 42" >
+<g>
+ <path fill="#C9E8FB" d="M24.932,13.053V8.795H11.553v24.411l11.515,0l6.162-6.162l-0.04-13.991H24.932z M17.652,24.783H14.45
+ v-0.801h3.201V24.783z M26.353,21.4H14.45V20.6h11.902V21.4z M26.353,18.018H14.45v-0.801h11.902V18.018z"/>
+ <polygon fill="#0E3A5A" points="30.89,13.063 29.181,11.354 26.633,11.354 26.633,8.806 24.922,7.096 9.853,7.096 9.853,34.905
+ 21.369,34.905 23.068,33.206 11.553,33.206 11.553,8.795 24.932,8.795 24.932,13.053 29.19,13.053 29.23,27.044 30.925,25.348 "/>
+ <rect x="14.45" y="17.217" fill="#0E3A5A" width="11.902" height="0.801"/>
+ <rect x="14.45" y="20.6" fill="#0E3A5A" width="11.902" height="0.801"/>
+ <rect x="14.45" y="23.982" fill="#0E3A5A" width="3.201" height="0.801"/>
+</g>
+</svg>
diff --git a/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/types/XmlExplorerFileType.java b/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/types/XmlExplorerFileType.java
new file mode 100644
index 0000000..f23d39d
--- /dev/null
+++ b/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/types/XmlExplorerFileType.java
@@ -0,0 +1,68 @@
+/*
+ * 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.xml.types;
+
+import org.apache.hop.core.Props;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.HopFileTypePlugin;
+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.IExplorerFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileType;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.Properties;
+
+@HopFileTypePlugin(
+ id = "XmlExplorerFileType",
+ name = "XML File Type",
+ description = "XML file handling in the explorer perspective",
+ image = "add_xml.svg")
+public class XmlExplorerFileType extends BaseExplorerFileType<XmlExplorerFileTypeHandler>
+ implements IExplorerFileType<XmlExplorerFileTypeHandler> {
+
+ public XmlExplorerFileType() {
+ super("XML file", ".xml", new String[] {"*.xml"}, new String[] {"XML files"}, new Properties());
+ }
+
+ @Override
+ public IHopFileTypeHandler newFile(HopGui hopGui, IVariables parentVariableSpace)
+ throws HopException {
+ return new EmptyHopFileTypeHandler();
+ }
+
+ @Override
+ public XmlExplorerFileTypeHandler createFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file) {
+ return new XmlExplorerFileTypeHandler(hopGui, perspective, file);
+ }
+}
diff --git a/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/types/XmlExplorerFileTypeHandler.java b/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/types/XmlExplorerFileTypeHandler.java
new file mode 100644
index 0000000..fd7393e
--- /dev/null
+++ b/plugins/transforms/xml/src/main/java/org/apache/hop/pipeline/transforms/xml/types/XmlExplorerFileTypeHandler.java
@@ -0,0 +1,80 @@
+/*
+ * 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.xml.types;
+
+import org.apache.hop.core.Props;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+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.IExplorerFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileTypeHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+/**
+ * How do we handle an SVG file in file explorer perspective?
+ */
+public class XmlExplorerFileTypeHandler extends BaseExplorerFileTypeHandler implements IExplorerFileTypeHandler {
+
+ public XmlExplorerFileTypeHandler( HopGui hopGui, ExplorerPerspective perspective, ExplorerFile explorerFile ) {
+ super( hopGui, perspective, explorerFile );
+ }
+
+ @Override
+ public void renderFile(Composite composite) {
+ // Render the file by simply showing the XML content as a text widget...
+ //
+ Text wXml = new Text(composite, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ PropsUi.getInstance().setLook(wXml, Props.WIDGET_STYLE_FIXED);
+ wXml.setEditable(false);
+ FormData fdXml = new FormData();
+ fdXml.left = new FormAttachment(0, 0);
+ fdXml.right = new FormAttachment(100, 0);
+ fdXml.top = new FormAttachment(0, 0);
+ fdXml.bottom = new FormAttachment(100, 0);
+ wXml.setLayoutData(fdXml);
+
+ // TODO: add bottom section to show status, size, cursor position...
+ //
+
+ // Load the content of the XML file...
+ //
+ File file = new File(explorerFile.getFilename());
+ if (file.exists()) {
+ try {
+ String contents = new String( Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
+ wXml.setText(contents);
+ } catch (Exception e) {
+ LogChannel.UI.logError(
+ "Error reading contents of file '" + explorerFile.getFilename() + "'", e);
+ }
+ }
+ }
+
+}
diff --git a/ui/src/main/java/org/apache/hop/core/SwtUniversalImageSvg.java b/ui/src/main/java/org/apache/hop/core/SwtUniversalImageSvg.java
index 7f5691a..36585e0 100644
--- a/ui/src/main/java/org/apache/hop/core/SwtUniversalImageSvg.java
+++ b/ui/src/main/java/org/apache/hop/core/SwtUniversalImageSvg.java
@@ -57,10 +57,14 @@ public class SwtUniversalImageSvg extends SwtUniversalImage {
}
public SwtUniversalImageSvg(SvgImage svg) {
+ this(svg, false);
+ }
+
+ public SwtUniversalImageSvg(SvgImage svg, boolean keepOriginal) {
UserAgentAdapter userAgentAdapter = new UserAgentAdapter();
GVTBuilder builder = new GVTBuilder();
- if (PropsUi.getInstance().isDarkMode()) {
+ if (!keepOriginal && PropsUi.getInstance().isDarkMode()) {
DOMImplementation domImplementation = SVGDOMImplementation.getDOMImplementation();
SVGDocument clonedDocument =
(SVGDocument) DOMUtilities.deepCloneDocument(svg.getDocument(), domImplementation);
diff --git a/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataFileType.java b/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataFileType.java
index 4a245bf..923d004 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataFileType.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataFileType.java
@@ -98,4 +98,8 @@ public class MetadataFileType implements IHopFileType {
List<IGuiContextHandler> handlers = new ArrayList<>();
return handlers;
}
+
+ @Override public String getFileTypeImage() {
+ return "ui/images/metadata.svg";
+ }
}
diff --git a/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataFileTypeHandler.java b/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataFileTypeHandler.java
index db4f1c2..897f3b4 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataFileTypeHandler.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataFileTypeHandler.java
@@ -31,7 +31,7 @@ import java.util.Map;
public class MetadataFileTypeHandler implements IHopFileTypeHandler {
- private static final IHopFileType<?> fileType = new MetadataFileType();
+ private static final IHopFileType fileType = new MetadataFileType();
public MetadataFileTypeHandler() {
@@ -48,7 +48,7 @@ public class MetadataFileTypeHandler implements IHopFileTypeHandler {
@Override public void setName( String name ) {
}
- @Override public IHopFileType<?> getFileType() {
+ @Override public IHopFileType getFileType() {
return fileType;
}
diff --git a/ui/src/main/java/org/apache/hop/ui/core/vfs/HopVfsFileDialog.java b/ui/src/main/java/org/apache/hop/ui/core/vfs/HopVfsFileDialog.java
index f62019b..cdb51b8 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/vfs/HopVfsFileDialog.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/vfs/HopVfsFileDialog.java
@@ -917,7 +917,7 @@ public class HopVfsFileDialog implements IFileDialog, IDirectoryDialog {
private Image getFileImage(FileObject file) {
try {
- IHopFileType<?> fileType =
+ IHopFileType fileType =
HopFileTypeRegistry.getInstance().findHopFileType(file.getName().getBaseName());
if (fileType != null) {
IPlugin plugin =
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/HopGui.java b/ui/src/main/java/org/apache/hop/ui/hopgui/HopGui.java
index 6a601ff..66e26c8 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/HopGui.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/HopGui.java
@@ -1054,7 +1054,7 @@ public class HopGui
* @param running set this to true if the current file is running
* @param paused set this to true if the current file is paused
*/
- public void handleFileCapabilities(IHopFileType<?> fileType, boolean running, boolean paused) {
+ public void handleFileCapabilities(IHopFileType fileType, boolean running, boolean paused) {
mainMenuWidgets.enableMenuItem(fileType, ID_MAIN_MENU_FILE_SAVE, IHopFileType.CAPABILITY_SAVE);
mainMenuWidgets.enableMenuItem(
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/HopGuiExtensionPoint.java b/ui/src/main/java/org/apache/hop/ui/hopgui/HopGuiExtensionPoint.java
index d38ec27..edb0260 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/HopGuiExtensionPoint.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/HopGuiExtensionPoint.java
@@ -21,6 +21,7 @@ import org.apache.hop.ui.hopgui.delegates.HopGuiDirectorySelectedExtension;
import org.apache.hop.ui.hopgui.delegates.HopGuiFileDialogExtension;
import org.apache.hop.ui.hopgui.delegates.HopGuiFileOpenedExtension;
import org.apache.hop.ui.hopgui.file.pipeline.HopGuiPipelineGraph;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
public enum HopGuiExtensionPoint {
@@ -31,6 +32,8 @@ public enum HopGuiExtensionPoint {
HopGuiFileDirectoryDialog( "Called before a DirectoryDialog is presented", HopGuiFileDialogExtension.class ),
HopGuiDirectorySelected( "Called after a folder is selected in the DirectoryDialog", HopGuiDirectorySelectedExtension.class ),
+
+ HopGuiDetermineExplorerRoot( "Determine the root folder of the explorer perspective", ExplorerPerspective.DetermineRootFolderExtension.class ),
;
public String id;
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiFileDelegate.java b/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiFileDelegate.java
index f1f9164..2f2ea0c 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiFileDelegate.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiFileDelegate.java
@@ -94,7 +94,7 @@ public class HopGuiFileDelegate {
public IHopFileTypeHandler fileOpen(String filename) throws Exception {
HopFileTypeRegistry fileRegistry = HopFileTypeRegistry.getInstance();
- IHopFileType<?> hopFile = fileRegistry.findHopFileType(filename);
+ IHopFileType hopFile = fileRegistry.findHopFileType(filename);
if (hopFile == null) {
throw new HopException(
"We looked at "
@@ -122,7 +122,7 @@ public class HopGuiFileDelegate {
public String fileSaveAs() {
try {
IHopFileTypeHandler typeHandler = getActiveFileTypeHandler();
- IHopFileType<?> fileType = typeHandler.getFileType();
+ IHopFileType fileType = typeHandler.getFileType();
if (!fileType.hasCapability(IHopFileType.CAPABILITY_SAVE_AS)) {
return null;
}
@@ -152,7 +152,7 @@ public class HopGuiFileDelegate {
public void fileSave() {
try {
IHopFileTypeHandler typeHandler = getActiveFileTypeHandler();
- IHopFileType<?> fileType = typeHandler.getFileType();
+ IHopFileType fileType = typeHandler.getFileType();
if (fileType.hasCapability(IHopFileType.CAPABILITY_SAVE)) {
if (StringUtils.isEmpty(typeHandler.getFilename())) {
// Ask for the filename: saveAs
@@ -171,7 +171,7 @@ public class HopGuiFileDelegate {
try {
IHopPerspective perspective = hopGui.getActivePerspective();
IHopFileTypeHandler typeHandler = getActiveFileTypeHandler();
- IHopFileType<?> fileType = typeHandler.getFileType();
+ IHopFileType fileType = typeHandler.getFileType();
if (fileType.hasCapability(IHopFileType.CAPABILITY_CLOSE)) {
perspective.remove(typeHandler);
}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/file/HopFileTypeBase.java b/ui/src/main/java/org/apache/hop/ui/hopgui/file/HopFileTypeBase.java
index 2c054d2..9e59816 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/file/HopFileTypeBase.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/file/HopFileTypeBase.java
@@ -25,7 +25,11 @@ import org.apache.hop.core.vfs.HopVfs;
import org.apache.hop.core.xml.IXml;
import java.util.Properties;
-public abstract class HopFileTypeBase<T extends IXml> implements IHopFileType<T> {
+public abstract class HopFileTypeBase implements IHopFileType {
+
+ @Override
+ public abstract String getName();
+
@Override
public abstract Properties getCapabilities();
@@ -37,10 +41,7 @@ public abstract class HopFileTypeBase<T extends IXml> implements IHopFileType<T>
if ( obj == this ) {
return true;
}
- if ( obj.getClass().equals( this.getClass() ) ) {
- return true; // same class is enough
- }
- return false;
+ return obj.getClass().equals( this.getClass() ); // same class is enough
}
@Override
@@ -81,4 +82,6 @@ public abstract class HopFileTypeBase<T extends IXml> implements IHopFileType<T>
}
return "true".equalsIgnoreCase( available.toString() );
}
+
+
}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/file/IHopFileType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/file/IHopFileType.java
index e7bc4f9..e48da0b 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/file/IHopFileType.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/file/IHopFileType.java
@@ -20,14 +20,14 @@ package org.apache.hop.ui.hopgui.file;
import org.apache.hop.core.exception.HopException;
import org.apache.hop.core.file.IHasFilename;
import org.apache.hop.core.variables.IVariables;
-import org.apache.hop.core.xml.IXml;
import org.apache.hop.ui.hopgui.HopGui;
import org.apache.hop.ui.hopgui.context.IGuiContextHandler;
+import org.apache.hop.ui.hopgui.perspective.IHopPerspective;
import java.util.List;
import java.util.Properties;
-public interface IHopFileType<T extends IXml> {
+public interface IHopFileType {
String CAPABILITY_NEW = "New";
String CAPABILITY_SAVE = "Save";
@@ -48,31 +48,23 @@ public interface IHopFileType<T extends IXml> {
String CAPABILITY_FILE_HISTORY = "FileHistory";
- /**
- * @return The name of this file type
- */
+ /** @return The name of this file type */
String getName();
/**
* Returns the default file extension in lowercase prefixed with dot (.xxx) for this file type.
- *
+ *
* @return The default file extension
*/
String getDefaultFileExtension();
-
- /**
- * @return The file type extensions.
- */
+
+ /** @return The file type extensions. */
String[] getFilterExtensions();
- /**
- * @return The file names (matching the extensions)
- */
+ /** @return The file names (matching the extensions) */
String[] getFilterNames();
- /**
- * @return The capabilities of this file handler
- */
+ /** @return The capabilities of this file handler */
Properties getCapabilities();
/**
@@ -81,31 +73,32 @@ public interface IHopFileType<T extends IXml> {
* @param capability The capability to check
* @return True if the capability is set to any non-null value
*/
- boolean hasCapability( String capability );
+ boolean hasCapability(String capability);
/**
* Load and display the file
*
- * @param hopGui The hop GUI to reference
- * @param filename The filename to load
+ * @param hopGui The hop GUI to reference
+ * @param filename The filename to load
* @param parentVariableSpace The parent variablespace to inherit from
* @return The hop file handler
*/
- IHopFileTypeHandler openFile( HopGui hopGui, String filename, IVariables parentVariableSpace ) throws HopException;
+ IHopFileTypeHandler openFile(HopGui hopGui, String filename, IVariables parentVariableSpace)
+ throws HopException;
- IHopFileTypeHandler newFile( HopGui hopGui, IVariables parentVariableSpace ) throws HopException;
+ IHopFileTypeHandler newFile(HopGui hopGui, IVariables parentVariableSpace) throws HopException;
/**
- * Look at the given file and see if it's handled by this type.
- * Usually this is done by simply looking at the file extension.
- * In rare cases we look at the content.
+ * Look at the given file and see if it's handled by this type. Usually this is done by simply
+ * looking at the file extension. In rare cases we look at the content.
*
- * @param filename The filename
+ * @param filename The filename
* @param checkContent True if we want to look inside the file content
* @return true if this HopFile is handling the file
- * @throws HopException In case something goes wrong like: file doesn't exist, a permission problem, ...
+ * @throws HopException In case something goes wrong like: file doesn't exist, a permission
+ * problem, ...
*/
- boolean isHandledBy( String filename, boolean checkContent ) throws HopException;
+ boolean isHandledBy(String filename, boolean checkContent) throws HopException;
/**
* Checks whether or not this file type supports the given metadata class
@@ -113,10 +106,18 @@ public interface IHopFileType<T extends IXml> {
* @param metaObject The object to verify support for
* @return
*/
- boolean supportsFile( IHasFilename metaObject );
+ boolean supportsFile(IHasFilename metaObject);
/**
- * @return A list of context handlers allowing you to see all the actions that can be taken with the current file type. (CRUD, ...)
+ * @return A list of context handlers allowing you to see all the actions that can be taken with
+ * the current file type. (CRUD, ...)
*/
List<IGuiContextHandler> getContextHandlers();
+
+ /**
+ * The icon image for this file type
+ *
+ * @return The path to the SVG file, a logo for this file type
+ */
+ String getFileTypeImage();
}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/file/empty/EmptyFileType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/file/empty/EmptyFileType.java
index 2e8d3dd..6f45846 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/file/empty/EmptyFileType.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/file/empty/EmptyFileType.java
@@ -24,6 +24,7 @@ import org.apache.hop.ui.hopgui.HopGui;
import org.apache.hop.ui.hopgui.context.IGuiContextHandler;
import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
import org.apache.hop.ui.hopgui.file.IHopFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.IExplorerFilePaintListener;
import java.util.ArrayList;
import java.util.List;
@@ -31,7 +32,7 @@ import java.util.Properties;
public class EmptyFileType implements IHopFileType {
@Override public String getName() {
- return null;
+ return "-";
}
@Override public String getDefaultFileExtension() {
@@ -74,4 +75,8 @@ public class EmptyFileType implements IHopFileType {
List<IGuiContextHandler> handlers = new ArrayList<>();
return handlers;
}
+
+ @Override public String getFileTypeImage() {
+ return "ui/images/file.svg";
+ }
}
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 78844c3..dda6055 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
@@ -52,7 +52,7 @@ import java.util.Properties;
description = "The pipeline file information for the Hop GUI",
image="ui/images/pipeline.svg"
)
-public class HopPipelineFileType<T extends PipelineMeta> extends HopFileTypeBase<T> implements IHopFileType<T> {
+public class HopPipelineFileType<T extends PipelineMeta> extends HopFileTypeBase implements IHopFileType {
public static final String PIPELINE_FILE_TYPE_DESCRIPTION = "Pipeline";
@@ -208,4 +208,8 @@ public class HopPipelineFileType<T extends PipelineMeta> extends HopFileTypeBase
handlers.add( new GuiContextHandler( ACTION_ID_NEW_PIPELINE, Arrays.asList(newAction) ) );
return handlers;
}
+
+ @Override public String getFileTypeImage() {
+ return "ui/images/pipeline.svg";
+ }
}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopWorkflowFileType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopWorkflowFileType.java
index f97b198..5fe18e5 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopWorkflowFileType.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopWorkflowFileType.java
@@ -53,7 +53,7 @@ import java.util.Properties;
description = "The workflow file information for the Hop GUI",
image="ui/images/workflow.svg"
)
-public class HopWorkflowFileType<T extends WorkflowMeta> extends HopFileTypeBase<T> implements IHopFileType<T> {
+public class HopWorkflowFileType<T extends WorkflowMeta> extends HopFileTypeBase implements IHopFileType {
public static final String WORKFLOW_FILE_TYPE_DESCRIPTION = "Workflow";
@@ -216,4 +216,8 @@ public class HopWorkflowFileType<T extends WorkflowMeta> extends HopFileTypeBase
return handlers;
}
+
+ @Override public String getFileTypeImage() {
+ return "ui/images/workflow.svg";
+ }
}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/HopPerspectiveManager.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/HopPerspectiveManager.java
index 1edc30e..c2ea347 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/HopPerspectiveManager.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/HopPerspectiveManager.java
@@ -79,9 +79,9 @@ public class HopPerspectiveManager {
* @param fileMetadata
* @return
*/
- public IHopFileType<?> findFileTypeHandler( IHasFilename fileMetadata ) {
+ public IHopFileType findFileTypeHandler( IHasFilename fileMetadata ) {
for ( IHopPerspective perspective : getPerspectives() ) {
- for ( IHopFileType<?> fileType : perspective.getSupportedHopFileTypes() ) {
+ for ( IHopFileType fileType : perspective.getSupportedHopFileTypes() ) {
if ( fileType.supportsFile( fileMetadata ) ) {
return fileType;
}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerFile.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerFile.java
new file mode 100644
index 0000000..70e2992
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerFile.java
@@ -0,0 +1,198 @@
+/*
+ * 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.hopgui.perspective.explorer;
+
+import org.apache.hop.core.changed.IChanged;
+import org.apache.hop.core.listeners.IContentChangedListener;
+import org.apache.hop.ui.hopgui.file.IHopFileType;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.IExplorerFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.IExplorerFileTypeHandler;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class ExplorerFile {
+
+ private String name;
+ private Image tabImage;
+ private String filename;
+ private IExplorerFileType fileType;
+ private IExplorerFileTypeHandler fileTypeHandler;
+ private boolean changed;
+ private List<IContentChangedListener> contentChangedListeners;
+
+ public ExplorerFile() {
+ contentChangedListeners = new ArrayList<>();
+ }
+
+ public ExplorerFile( String name, Image tabImage, String filename, IExplorerFileType fileType, IExplorerFileTypeHandler fileTypeHandler ) {
+ this();
+ this.name = name;
+ this.tabImage = tabImage;
+ this.filename = filename;
+ this.fileType = fileType;
+ this.fileTypeHandler = fileTypeHandler;
+ }
+
+ @Override public boolean equals( Object o ) {
+ if ( this == o ) {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
+ ExplorerFile that = (ExplorerFile) o;
+ return Objects.equals( filename, that.filename );
+ }
+
+ @Override public int hashCode() {
+ return Objects.hash( filename );
+ }
+
+ /**
+ * Gets tabName
+ *
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name The name to set
+ */
+ public void setName( String name ) {
+ this.name = name;
+ }
+
+ /**
+ * Gets tabImage
+ *
+ * @return value of tabImage
+ */
+ public Image getTabImage() {
+ return tabImage;
+ }
+
+ /**
+ * @param tabImage The tabImage to set
+ */
+ public void setTabImage( Image tabImage ) {
+ this.tabImage = tabImage;
+ }
+
+ /**
+ * Gets filename
+ *
+ * @return value of filename
+ */
+ public String getFilename() {
+ return filename;
+ }
+
+ /**
+ * @param filename The filename to set
+ */
+ public void setFilename( String filename ) {
+ this.filename = filename;
+ }
+
+ /**
+ * Gets fileType
+ *
+ * @return value of fileType
+ */
+ public IExplorerFileType getFileType() {
+ return fileType;
+ }
+
+ /**
+ * @param fileType The fileType to set
+ */
+ public void setFileType( IExplorerFileType fileType ) {
+ this.fileType = fileType;
+ }
+
+ /**
+ * Gets fileTypeHandler
+ *
+ * @return value of fileTypeHandler
+ */
+ public IExplorerFileTypeHandler getFileTypeHandler() {
+ return fileTypeHandler;
+ }
+
+ /**
+ * @param fileTypeHandler The fileTypeHandler to set
+ */
+ public void setFileTypeHandler( IExplorerFileTypeHandler fileTypeHandler ) {
+ this.fileTypeHandler = fileTypeHandler;
+ }
+
+ /**
+ * Gets changed
+ *
+ * @return value of changed
+ */
+ public boolean isChanged() {
+ return changed;
+ }
+
+ /**
+ * Flag the file as changed
+ */
+ public void setChanged() {
+ if (!changed) {
+ this.changed = true;
+ for (IContentChangedListener listener : contentChangedListeners) {
+ listener.contentChanged(this);
+ }
+ }
+ }
+
+ public void clearChanged() {
+ if (changed) {
+ this.changed = false;
+ for (IContentChangedListener listener : contentChangedListeners) {
+ listener.contentSafe(this);
+ }
+ }
+ }
+
+ /**
+ * Gets contentChangedListeners
+ *
+ * @return value of contentChangedListeners
+ */
+ public List<IContentChangedListener> getContentChangedListeners() {
+ return contentChangedListeners;
+ }
+
+ /**
+ * Be informed if content changed.
+ * @param listener
+ */
+ public void addContentChangedListener(IContentChangedListener listener) {
+ contentChangedListeners.add(listener);
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerPerspective.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerPerspective.java
new file mode 100644
index 0000000..de85eb4
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerPerspective.java
@@ -0,0 +1,812 @@
+/*
+ * 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.hopgui.perspective.explorer;
+
+import org.apache.commons.vfs2.FileObject;
+import org.apache.hop.core.Const;
+import org.apache.hop.core.Props;
+import org.apache.hop.core.SwtUniversalImageSvg;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.extension.ExtensionPointHandler;
+import org.apache.hop.core.gui.plugin.GuiPlugin;
+import org.apache.hop.core.gui.plugin.toolbar.GuiToolbarElement;
+import org.apache.hop.core.listeners.IContentChangedListener;
+import org.apache.hop.core.plugins.IPlugin;
+import org.apache.hop.core.plugins.PluginRegistry;
+import org.apache.hop.core.search.ISearchable;
+import org.apache.hop.core.svg.SvgCache;
+import org.apache.hop.core.svg.SvgCacheEntry;
+import org.apache.hop.core.svg.SvgFile;
+import org.apache.hop.core.svg.SvgImage;
+import org.apache.hop.core.vfs.HopVfs;
+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.gui.GuiResource;
+import org.apache.hop.ui.core.gui.GuiToolbarWidgets;
+import org.apache.hop.ui.core.widget.TabFolderReorder;
+import org.apache.hop.ui.core.widget.TreeMemory;
+import org.apache.hop.ui.core.widget.TreeToolTipSupport;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.HopGuiExtensionPoint;
+import org.apache.hop.ui.hopgui.context.IGuiContextHandler;
+import org.apache.hop.ui.hopgui.file.HopFileTypePluginType;
+import org.apache.hop.ui.hopgui.file.IHopFileType;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+import org.apache.hop.ui.hopgui.file.empty.EmptyFileType;
+import org.apache.hop.ui.hopgui.file.empty.EmptyHopFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.HopPerspectivePlugin;
+import org.apache.hop.ui.hopgui.perspective.IHopPerspective;
+import org.apache.hop.ui.hopgui.perspective.TabItemHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.ExplorerFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.IExplorerFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.IExplorerFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.GenericFileType;
+import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabFolder2Adapter;
+import org.eclipse.swt.custom.CTabFolderEvent;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.custom.TreeEditor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.layout.FormLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@HopPerspectivePlugin(
+ id = "300-HopExplorerPerspective",
+ name = "File Explorer",
+ description = "The Hop Explorer Perspective",
+ image = "ui/images/folder.svg")
+@GuiPlugin(description = "A file explorer for your current project")
+public class ExplorerPerspective implements IHopPerspective {
+
+ private static final String FILE_EXPLORER_TREE = "File explorer tree";
+
+ public static final String GUI_PLUGIN_TOOLBAR_PARENT_ID = "ExplorerPerspective-Toolbar";
+
+ public static final String TOOLBAR_ITEM_EDIT = "ExplorerPerspective-Toolbar-10010-Edit";
+ public static final String TOOLBAR_ITEM_DUPLICATE = "ExplorerPerspective-Toolbar-10030-Duplicate";
+ public static final String TOOLBAR_ITEM_DELETE = "ExplorerPerspective-Toolbar-10040-Delete";
+ public static final String TOOLBAR_ITEM_REFRESH = "ExplorerPerspective-Toolbar-10100-Refresh";
+
+ private static ExplorerPerspective instance;
+
+ public static ExplorerPerspective getInstance() {
+ return instance;
+ }
+
+ private HopGui hopGui;
+ private SashForm sash;
+ private Tree tree;
+ private TreeEditor treeEditor;
+ private CTabFolder tabFolder;
+ private ToolBar toolBar;
+ private GuiToolbarWidgets toolBarWidgets;
+
+ private List<ExplorerFile> files = new ArrayList<>();
+
+ private final EmptyFileType emptyFileType;
+ private final ExplorerFileType explorerFileType;
+
+ private String rootFolder;
+ private String rootName;
+
+ private class TreeItemFolder {
+ public TreeItem treeItem;
+ public String path;
+ public String name;
+ public IHopFileType fileType;
+
+ public TreeItemFolder(TreeItem treeItem, String path, String name, IHopFileType fileType) {
+ this.treeItem = treeItem;
+ this.path = path;
+ this.name = name;
+ this.fileType = fileType;
+ }
+ }
+
+ private Map<String, TreeItemFolder> treeItemFolderMap;
+
+ private List<IExplorerFilePaintListener> filePaintListeners;
+
+ private List<IHopFileType> fileTypes;
+
+ private Map<String, Image> typeImageMap;
+
+ public ExplorerPerspective() {
+ instance = this;
+
+ this.emptyFileType = new EmptyFileType();
+ this.explorerFileType = new ExplorerFileType();
+
+ this.treeItemFolderMap = new HashMap<>();
+ this.filePaintListeners = new ArrayList<>();
+ this.typeImageMap = new HashMap<>();
+ }
+
+ @Override
+ public String getId() {
+ return "explorer-perspective";
+ }
+
+ @Override
+ public void activate() {
+ hopGui.setActivePerspective(this);
+ }
+
+ @Override
+ public void perspectiveActivated() {
+ this.refresh();
+ this.updateSelection();
+
+ // If all editor are closed
+ //
+ if (tabFolder.getItemCount() == 0) {
+ HopGui.getInstance().handleFileCapabilities(emptyFileType, false, false);
+ } else {
+ HopGui.getInstance().handleFileCapabilities(explorerFileType, false, false);
+ }
+ }
+
+ @Override
+ public boolean isActive() {
+ return hopGui.isActivePerspective(this);
+ }
+
+ @Override
+ public List<IHopFileType> getSupportedHopFileTypes() {
+ return Arrays.asList(explorerFileType);
+ }
+
+ @Override
+ public void initialize(HopGui hopGui, Composite parent) {
+ this.hopGui = hopGui;
+
+ determineRootFolderName(hopGui);
+ loadFileTypes();
+ loadTypeImages(parent);
+
+ // Split tree and editor
+ //
+ sash = new SashForm(parent, SWT.HORIZONTAL);
+ FormData fdSash = new FormData();
+ fdSash.left = new FormAttachment(0, 0);
+ fdSash.top = new FormAttachment(0, 0);
+ fdSash.right = new FormAttachment(100, 0);
+ fdSash.bottom = new FormAttachment(100, 0);
+ sash.setLayoutData(fdSash);
+
+ createTree(sash);
+ createTabFolder(sash);
+
+ sash.setWeights(new int[] {20, 80});
+
+ // TODO: Refresh the root folder when it comes back into focus and when it's needed
+ //
+
+ }
+
+ private void loadFileTypes() {
+ fileTypes = new ArrayList<>();
+ PluginRegistry registry = PluginRegistry.getInstance();
+ List<IPlugin> plugins = PluginRegistry.getInstance().getPlugins(HopFileTypePluginType.class);
+ for (IPlugin plugin : plugins) {
+ try {
+ IHopFileType fileType = (IHopFileType) registry.loadClass(plugin);
+ fileTypes.add(fileType);
+ } catch (Exception e) {
+ hopGui.getLog().logError("Unable to load file type plugin: " + plugin.getIds()[0], e);
+ }
+ }
+ // Keep as last in the list...
+ fileTypes.add(new GenericFileType());
+ }
+
+ private void loadTypeImages(Composite parentComposite) {
+ typeImageMap = new HashMap<>();
+ int iconSize = (int) (PropsUi.getInstance().getZoomFactor() * 16);
+
+ for (IHopFileType fileType : fileTypes) {
+ String imageFilename = fileType.getFileTypeImage();
+ if (imageFilename != null) {
+ try {
+ SvgCacheEntry svgCacheEntry =
+ SvgCache.loadSvg(new SvgFile(imageFilename, fileType.getClass().getClassLoader()));
+ SwtUniversalImageSvg imageSvg =
+ new SwtUniversalImageSvg(new SvgImage(svgCacheEntry.getSvgDocument()));
+ Image image = imageSvg.getAsBitmapForSize(hopGui.getDisplay(), iconSize, iconSize);
+ typeImageMap.put(fileType.getName(), image);
+ } catch (Exception e) {
+ hopGui
+ .getLog()
+ .logError(
+ "Error loading image : '"
+ + imageFilename
+ + "' for type '"
+ + fileType.getName()
+ + "'",
+ e);
+ }
+ }
+ }
+ // Properly dispose images when done...
+ //
+ parentComposite.addListener(
+ SWT.Dispose,
+ e -> {
+ for (Image image : typeImageMap.values()) {
+ image.dispose();
+ }
+ });
+ }
+
+ public class DetermineRootFolderExtension {
+ public HopGui hopGui;
+ public String rootFolder;
+ public String rootName;
+
+ public DetermineRootFolderExtension(HopGui hopGui, String rootFolder, String rootName) {
+ this.hopGui = hopGui;
+ this.rootFolder = rootFolder;
+ this.rootName = rootName;
+ }
+ }
+
+ public void determineRootFolderName(HopGui hopGui) {
+
+ rootFolder = hopGui.getVariables().getVariable("user.home");
+ rootName = "Home folder";
+
+ DetermineRootFolderExtension ext =
+ new DetermineRootFolderExtension(hopGui, rootFolder, rootName);
+ try {
+ ExtensionPointHandler.callExtensionPoint(
+ hopGui.getLog(),
+ hopGui.getVariables(),
+ HopGuiExtensionPoint.HopGuiDetermineExplorerRoot.id,
+ ext);
+ rootFolder = ext.rootFolder;
+ rootName = ext.rootName;
+ } catch (Exception e) {
+ new ErrorDialog(
+ getShell(), "Error", "Error getting root folder/name of explorer perspective", e);
+ }
+ }
+
+ protected void createTree(Composite parent) {
+ PropsUi props = PropsUi.getInstance();
+
+ // Create composite
+ //
+ Composite composite = new Composite(parent, SWT.BORDER);
+ FormLayout layout = new FormLayout();
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ composite.setLayout(layout);
+
+ // Create toolbar
+ //
+ toolBar = new ToolBar(composite, SWT.WRAP | SWT.LEFT | SWT.HORIZONTAL);
+ toolBarWidgets = new GuiToolbarWidgets();
+ toolBarWidgets.registerGuiPluginObject(this);
+ toolBarWidgets.createToolbarWidgets(toolBar, GUI_PLUGIN_TOOLBAR_PARENT_ID);
+ FormData layoutData = new FormData();
+ layoutData.left = new FormAttachment(0, 0);
+ layoutData.top = new FormAttachment(0, 0);
+ layoutData.right = new FormAttachment(100, 0);
+ toolBar.setLayoutData(layoutData);
+ toolBar.pack();
+ props.setLook(toolBar, Props.WIDGET_STYLE_TOOLBAR);
+
+ tree = new Tree(composite, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL);
+ tree.setHeaderVisible(false);
+ tree.addListener(SWT.Selection, event -> updateSelection());
+ tree.addListener(SWT.DefaultSelection, this::openFile);
+ PropsUi.getInstance().setLook(tree);
+
+ FormData treeFormData = new FormData();
+ treeFormData.left = new FormAttachment(0, 0);
+ treeFormData.top = new FormAttachment(toolBar, 0);
+ treeFormData.right = new FormAttachment(100, 0);
+ treeFormData.bottom = new FormAttachment(100, 0);
+ tree.setLayoutData(treeFormData);
+
+ // Create Tree editor for rename
+ treeEditor = new TreeEditor(tree);
+ treeEditor.horizontalAlignment = SWT.LEFT;
+ treeEditor.grabHorizontal = true;
+
+ // Add on first level tooltip with metatada description
+ new TreeToolTipSupport(tree);
+
+ // Remember tree node expanded/Collapsed
+ TreeMemory.addTreeListener(tree, FILE_EXPLORER_TREE);
+ }
+
+ private void openFile(Event event) {
+ try {
+ if (event.item instanceof TreeItem) {
+ TreeItem item = (TreeItem) event.item;
+ TreeItemFolder tif = treeItemFolderMap.get(ConstUi.getTreePath(item, 0));
+ if (tif != null && tif.fileType != null) {
+ tif.fileType.openFile(hopGui, tif.path, hopGui.getVariables());
+ updateGui();
+ }
+ }
+ } catch (Exception e) {
+ new ErrorDialog(hopGui.getShell(), "Error", "Error opening file", e);
+ }
+ }
+
+ protected void createTabFolder(Composite parent) {
+ PropsUi props = PropsUi.getInstance();
+
+ tabFolder = new CTabFolder(parent, SWT.MULTI | SWT.BORDER);
+ tabFolder.addCTabFolder2Listener(
+ new CTabFolder2Adapter() {
+ @Override
+ public void close(CTabFolderEvent event) {
+ onTabClose(event);
+ }
+ });
+ tabFolder.addListener( SWT.Selection, event -> handleTabSelectionEvent( event ) );
+ props.setLook(tabFolder, Props.WIDGET_STYLE_TAB);
+
+ // Show/Hide tree
+ //
+ ToolBar toolBar = new ToolBar(tabFolder, SWT.FLAT);
+ final ToolItem item = new ToolItem(toolBar, SWT.PUSH);
+ item.setImage(GuiResource.getInstance().getImageMinimizePanel());
+ item.addListener(
+ SWT.Selection,
+ e -> {
+ if (sash.getMaximizedControl() == null) {
+ sash.setMaximizedControl(tabFolder);
+ item.setImage(GuiResource.getInstance().getImageMaximizePanel());
+ } else {
+ sash.setMaximizedControl(null);
+ item.setImage(GuiResource.getInstance().getImageMinimizePanel());
+ }
+ });
+ tabFolder.setTopRight(toolBar, SWT.RIGHT);
+
+ // Support reorder tab item
+ //
+ new TabFolderReorder(tabFolder);
+ }
+
+ /**
+ * Also select the corresponding file in the left hand tree...
+ *
+ * @param event
+ */
+ private void handleTabSelectionEvent( Event event ) {
+ if (event.item instanceof CTabItem) {
+ CTabItem tabItem = (CTabItem) event.item;
+ ExplorerFile explorerFile = (ExplorerFile) tabItem.getData();
+ selectInTree( explorerFile.getFilename() );
+ }
+ }
+
+ public CTabItem addFile(ExplorerFile explorerFile, IExplorerFileTypeHandler renderer) {
+ PropsUi props = PropsUi.getInstance();
+
+ // Create tab item
+ //
+ CTabItem tabItem = new CTabItem(tabFolder, SWT.CLOSE);
+ tabItem.setFont(tabFolder.getFont() );
+ tabItem.setText(Const.NVL(explorerFile.getName(), ""));
+ if (explorerFile.getTabImage() != null) {
+ tabItem.setImage(explorerFile.getTabImage());
+ } else {
+ tabItem.setImage(GuiResource.getInstance().getImageFile());
+ }
+ tabItem.setToolTipText(explorerFile.getFilename());
+ tabItem.setData(explorerFile);
+
+ // Set the tab bold if the file has changed and vice-versa
+ //
+ explorerFile.addContentChangedListener( new IContentChangedListener() {
+ @Override public void contentChanged( Object parentObject ) {
+ tabItem.setFont( GuiResource.getInstance().getFontBold() );
+ }
+
+ @Override public void contentSafe( Object parentObject ) {
+ tabItem.setFont( tabFolder.getFont() );
+ }
+ } );
+
+ // Create composite for editor and buttons
+ //
+ Composite composite = new Composite(tabFolder, SWT.NONE);
+ FormLayout layoutComposite = new FormLayout();
+ layoutComposite.marginWidth = Const.FORM_MARGIN;
+ layoutComposite.marginHeight = Const.FORM_MARGIN;
+ composite.setLayout(layoutComposite);
+ props.setLook(composite);
+
+ // This is usually done by the file type
+ //
+ renderer.renderFile( composite );
+
+ // Create file content area
+ //
+ Composite area = new Composite(composite, SWT.NONE);
+ FormLayout layoutArea = new FormLayout();
+ layoutArea.marginWidth = 0;
+ layoutArea.marginHeight = 0;
+ area.setLayout(layoutArea);
+ FormData fdArea = new FormData();
+ fdArea.left = new FormAttachment(0, 0);
+ fdArea.top = new FormAttachment(0, 0);
+ fdArea.right = new FormAttachment(100, 0);
+ fdArea.bottom = new FormAttachment(100, 0);
+
+ area.setLayoutData(fdArea);
+ props.setLook(area);
+
+ tabItem.setControl(composite);
+ tabItem.setData(explorerFile);
+
+ files.add(explorerFile);
+
+ // Activate perspective
+ //
+ this.activate();
+
+ updateGui();
+
+ // Switch to the tab
+ //
+ tabFolder.setSelection(tabItem);
+
+ selectInTree(explorerFile.getFilename());
+
+ return tabItem;
+ }
+
+ private void selectInTree( String filename ) {
+ for (TreeItemFolder tif : treeItemFolderMap.values()) {
+ if (tif.path.equals( filename )) {
+ tree.setSelection( tif.treeItem );
+ return;
+ }
+ }
+ }
+
+ public void setActiveFile(ExplorerFile file) {
+ for (CTabItem item : tabFolder.getItems()) {
+ if (item.getData().equals(file)) {
+ tabFolder.setSelection(item);
+ tabFolder.showItem(item);
+
+ HopGui.getInstance().handleFileCapabilities(explorerFileType, false, false);
+ }
+ }
+ }
+
+ public void closeFile(ExplorerFile explorerFile) {
+ for (CTabItem item : tabFolder.getItems()) {
+ if (item.getData().equals(explorerFile)) {
+ if (explorerFile.getFileTypeHandler().isCloseable()) {
+ item.dispose();
+ }
+ }
+ }
+ }
+
+ public ExplorerFile getActiveFile() {
+ if (tabFolder.getSelectionIndex() < 0) {
+ return null;
+ }
+
+ return (ExplorerFile) tabFolder.getSelection().getData();
+ }
+
+ @Override
+ public IHopFileTypeHandler getActiveFileTypeHandler() {
+ ExplorerFile explorerFile = getActiveFile();
+ if (explorerFile != null) {
+ return explorerFile.getFileTypeHandler();
+ }
+
+ return new EmptyHopFileTypeHandler();
+ }
+
+ @Override
+ public void setActiveFileTypeHandler(IHopFileTypeHandler fileTypeHandler) {
+ if (fileTypeHandler instanceof ExplorerFile) {
+ this.setActiveFile((ExplorerFile) fileTypeHandler);
+ }
+ }
+
+ protected void onTabClose(CTabFolderEvent event) {
+ CTabItem tabItem = (CTabItem) event.item;
+ ExplorerFile file = (ExplorerFile) tabItem.getData();
+
+ if (file.getFileTypeHandler().isCloseable()) {
+ files.remove(file);
+ tabItem.dispose();
+
+ // Refresh tree to remove bold
+ //
+ this.refresh();
+
+ // If all editor are closed
+ //
+ if (tabFolder.getItemCount() == 0) {
+ HopGui.getInstance().handleFileCapabilities(new EmptyFileType(), false, false);
+ }
+ updateGui();
+ } else {
+ // Ignore event if canceled
+ event.doit = false;
+ }
+ }
+
+ public void onNewFile() {}
+
+ boolean first = true;
+
+ @GuiToolbarElement(
+ root = GUI_PLUGIN_TOOLBAR_PARENT_ID,
+ id = TOOLBAR_ITEM_REFRESH,
+ toolTip = "Refresh",
+ image = "ui/images/refresh.svg")
+ public void refresh() {
+ try {
+ determineRootFolderName(hopGui);
+
+ tree.setRedraw(false);
+ tree.removeAll();
+ treeItemFolderMap.clear();
+
+ // Add the root element...
+ //
+ TreeItem rootItem = new TreeItem(tree, SWT.NONE);
+ rootItem.setText(Const.NVL(rootName, ""));
+ IHopFileType fileType = getFileType(rootFolder);
+ setItemImage(rootItem, fileType);
+ callPaintListeners(tree, rootItem, rootFolder, rootName, fileType);
+ addToFolderMap(rootItem, rootFolder, rootName, fileType);
+
+ refreshFolder(rootItem, rootFolder);
+
+ tree.setRedraw(true);
+
+ if (first) {
+ first = false;
+ // Set the top level items in the tree to be expanded
+ //
+ for (TreeItem item : tree.getItems()) {
+ item.setExpanded( true );
+ TreeMemory.getInstance().storeExpanded(FILE_EXPLORER_TREE, item, true);
+ }
+ } else {
+ TreeMemory.setExpandedFromMemory(tree, FILE_EXPLORER_TREE);
+ }
+ } catch (Exception e) {
+ new ErrorDialog(getShell(), "Error", "Error refreshing file explorer tree", e);
+ }
+ }
+
+ private void addToFolderMap(TreeItem treeItem, String path, String name, IHopFileType fileType) {
+ treeItemFolderMap.put(
+ ConstUi.getTreePath(treeItem, 0), new TreeItemFolder(treeItem, path, name, fileType));
+ }
+
+ private void setItemImage(TreeItem treeItem, IHopFileType fileType) {
+ Image image = typeImageMap.get(fileType.getName());
+ if (image != null) {
+ treeItem.setImage(image);
+ }
+ }
+
+ public Image getFileTypeImage(IHopFileType fileType) {
+ return typeImageMap.get(fileType.getName());
+ }
+
+ public IHopFileType getFileType(String path) throws HopException {
+
+ // TODO: get this list from the plugin registry...
+ //
+ for (IHopFileType hopFileType : fileTypes) {
+ // Only look at the extension of the file
+ //
+ if (hopFileType.isHandledBy(path, false)) {
+ return hopFileType;
+ }
+ }
+
+ return new EmptyFileType();
+ }
+
+ private void refreshFolder(TreeItem item, String path) {
+
+ try {
+ FileObject fileObject = HopVfs.getFileObject(path);
+ FileObject[] children = fileObject.getChildren();
+
+ // Sort by full path ascending
+ Arrays.sort(children, Comparator.comparing(Object::toString));
+
+ for (boolean folder : new boolean[] {true, false}) {
+ for (FileObject child : children) {
+ if (child.isHidden()) {
+ continue; // skip hidden files for now
+ }
+ if (child.isFolder() != folder) {
+ continue;
+ }
+
+ String childPath = child.getName().getPath();
+ String childName = child.getName().getBaseName();
+ IHopFileType fileType = getFileType(childPath);
+ TreeItem childItem = new TreeItem(item, SWT.NONE);
+ childItem.setText(childName);
+ setItemImage(childItem, fileType);
+ callPaintListeners(tree, childItem, childPath, childName, fileType);
+ addToFolderMap(childItem, childPath, childName, fileType);
+
+ // Recursively add children
+ //
+ if (child.isFolder()) {
+ refreshFolder(childItem, child.getName().getPath());
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ TreeItem treeItem = new TreeItem(item, SWT.NONE);
+ treeItem.setText("!!Error refreshing folder!!");
+ hopGui.getLog().logError("Error refresh folder '" + path + "'", e);
+ }
+ }
+
+ private void callPaintListeners(
+ Tree tree, TreeItem treeItem, String path, String name, IHopFileType fileType) {
+ for (IExplorerFilePaintListener filePaintListener : filePaintListeners) {
+ filePaintListener.filePainted(tree, treeItem, path, name);
+ }
+ }
+
+ protected void updateSelection() {
+
+ String objectKey = null;
+ TreeItemFolder tif = null;
+
+ if (tree.getSelectionCount() > 0) {
+ TreeItem selectedItem = tree.getSelection()[0];
+ objectKey = ConstUi.getTreePath(selectedItem, 0);
+ tif = treeItemFolderMap.get(objectKey);
+ }
+
+ toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_EDIT, tif != null);
+ toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_DUPLICATE, tif != null);
+ toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_DELETE, tif != null);
+ }
+
+ @Override
+ public boolean remove(IHopFileTypeHandler typeHandler) {
+ if (typeHandler instanceof ExplorerFile) {
+ ExplorerFile file = (ExplorerFile) typeHandler;
+
+ if (file.getFileTypeHandler().isCloseable()) {
+
+ files.remove(file);
+
+ for (CTabItem item : tabFolder.getItems()) {
+ if (file.equals(item.getData())) {
+ item.dispose();
+ }
+ }
+
+ // Refresh tree to remove bold
+ //
+ this.refresh();
+
+ // If all editor are closed
+ //
+ if (tabFolder.getItemCount() == 0) {
+ HopGui.getInstance().handleFileCapabilities(new EmptyFileType(), false, false);
+ }
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public List<TabItemHandler> getItems() {
+ return null;
+ }
+
+ @Override
+ public void navigateToPreviousFile() {
+ tabFolder.setSelection(tabFolder.getSelectionIndex() + 1);
+ }
+
+ @Override
+ public void navigateToNextFile() {
+ tabFolder.setSelection(tabFolder.getSelectionIndex() - 1);
+ }
+
+ @Override
+ public boolean hasNavigationPreviousFile() {
+ if (tabFolder.getItemCount() == 0) {
+ return false;
+ }
+ return tabFolder.getSelectionIndex() >= 1;
+ }
+
+ @Override
+ public boolean hasNavigationNextFile() {
+ if (tabFolder.getItemCount() == 0) {
+ return false;
+ }
+ return tabFolder.getSelectionIndex() < tabFolder.getItemCount();
+ }
+
+ @Override
+ public Control getControl() {
+ return sash;
+ }
+
+ protected Shell getShell() {
+ return hopGui.getShell();
+ }
+
+ @Override
+ public List<IGuiContextHandler> getContextHandlers() {
+ List<IGuiContextHandler> handlers = new ArrayList<>();
+ return handlers;
+ }
+
+ @Override
+ public List<ISearchable> getSearchables() {
+ List<ISearchable> searchables = new ArrayList<>();
+ return searchables;
+ }
+
+ public void updateGui() {
+ if (hopGui == null || toolBarWidgets == null || toolBar == null || toolBar.isDisposed()) {
+ return;
+ }
+ final IHopFileTypeHandler activeHandler = getActiveFileTypeHandler();
+ hopGui.getDisplay().asyncExec( () -> hopGui.handleFileCapabilities(activeHandler.getFileType(), false, false) );
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/IExplorerFileContentCallback.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/IExplorerFileContentCallback.java
new file mode 100644
index 0000000..79d76c2
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/IExplorerFileContentCallback.java
@@ -0,0 +1,24 @@
+/*
+ * 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.hopgui.perspective.explorer;
+
+public interface IExplorerFileContentCallback {
+
+ void getContent();
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/IExplorerFilePaintListener.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/IExplorerFilePaintListener.java
new file mode 100644
index 0000000..c1a75c2
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/IExplorerFilePaintListener.java
@@ -0,0 +1,31 @@
+/*
+ * 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.hopgui.perspective.explorer;
+
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+/**
+ * This interface allows you to adjust the painting of a Tree Item in the explorer perspective
+ */
+public interface IExplorerFilePaintListener {
+
+ void filePainted( Tree tree, TreeItem treeItem, String path, String name );
+
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataFileType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/ExplorerFileType.java
similarity index 90%
copy from ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataFileType.java
copy to ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/ExplorerFileType.java
index 4a245bf..c46ba33 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataFileType.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/ExplorerFileType.java
@@ -15,24 +15,23 @@
* limitations under the License.
*/
-package org.apache.hop.ui.core.metadata;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Properties;
+package org.apache.hop.ui.hopgui.perspective.explorer.file;
import org.apache.hop.core.exception.HopException;
import org.apache.hop.core.file.IHasFilename;
import org.apache.hop.core.variables.IVariables;
-import org.apache.hop.metadata.api.IHopMetadata;
import org.apache.hop.ui.hopgui.HopGui;
import org.apache.hop.ui.hopgui.context.IGuiContextHandler;
import org.apache.hop.ui.hopgui.file.IHopFileType;
import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
-public class MetadataFileType implements IHopFileType {
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+public class ExplorerFileType implements IHopFileType {
@Override public String getName() {
- return "meta";
+ return "explorer";
}
@Override
@@ -79,11 +78,11 @@ public class MetadataFileType implements IHopFileType {
}
@Override public IHopFileTypeHandler openFile( HopGui hopGui, String filename, IVariables parentVariableSpace ) throws HopException {
- return new MetadataFileTypeHandler();
+ return new ExplorerFileTypeHandler();
}
@Override public IHopFileTypeHandler newFile( HopGui hopGui, IVariables parentVariableSpace ) throws HopException {
- return new MetadataFileTypeHandler();
+ return new ExplorerFileTypeHandler();
}
@Override public boolean isHandledBy( String filename, boolean checkContent ) throws HopException {
@@ -98,4 +97,8 @@ public class MetadataFileType implements IHopFileType {
List<IGuiContextHandler> handlers = new ArrayList<>();
return handlers;
}
+
+ @Override public String getFileTypeImage() {
+ return "ui/images/exploreRepo.svg";
+ }
}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/ExplorerFileTypeHandler.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/ExplorerFileTypeHandler.java
new file mode 100644
index 0000000..6fab3df
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/ExplorerFileTypeHandler.java
@@ -0,0 +1,156 @@
+/*
+ * 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.hopgui.perspective.explorer.file;
+
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.core.variables.Variables;
+import org.apache.hop.ui.hopgui.context.IGuiContextHandler;
+import org.apache.hop.ui.hopgui.file.IHopFileType;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class ExplorerFileTypeHandler implements IHopFileTypeHandler {
+
+ private static final IHopFileType fileType = new ExplorerFileType();
+
+ private String filename;
+
+ public ExplorerFileTypeHandler() {}
+
+ @Override
+ public Object getSubject() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public void setName(String name) {}
+
+ @Override
+ public IHopFileType getFileType() {
+ return fileType;
+ }
+
+ @Override
+ public String getFilename() {
+ return filename;
+ }
+
+ @Override
+ public void setFilename(String filename) {}
+
+ @Override
+ public void save() throws HopException {}
+
+ @Override
+ public void saveAs(String filename) throws HopException {}
+
+ @Override
+ public void start() {}
+
+ @Override
+ public void stop() {}
+
+ @Override
+ public void pause() {}
+
+ @Override
+ public void resume() {}
+
+ @Override
+ public void preview() {}
+
+ @Override
+ public void debug() {}
+
+ @Override
+ public void redraw() {}
+
+ @Override
+ public void updateGui() {}
+
+ @Override
+ public void selectAll() {}
+
+ @Override
+ public void unselectAll() {}
+
+ @Override
+ public void copySelectedToClipboard() {}
+
+ @Override
+ public void cutSelectedToClipboard() {}
+
+ @Override
+ public void deleteSelected() {}
+
+ @Override
+ public void pasteFromClipboard() {}
+
+ @Override
+ public boolean isCloseable() {
+ return true;
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public boolean hasChanged() {
+ return false;
+ }
+
+ @Override
+ public void undo() {}
+
+ @Override
+ public void redo() {}
+
+ @Override
+ public Map<String, Object> getStateProperties() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public void applyStateProperties(Map<String, Object> stateProperties) {}
+
+ @Override
+ public List<IGuiContextHandler> getContextHandlers() {
+ List<IGuiContextHandler> handlers = new ArrayList<>();
+ return handlers;
+ }
+
+ /**
+ * Explorer doesn't have it's own variables. It should take it elsewhere.
+ *
+ * @return An empty variables set
+ */
+ @Override
+ public IVariables getVariables() {
+ return new Variables();
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/FileDetails.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/FileDetails.java
new file mode 100644
index 0000000..2974e06
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/FileDetails.java
@@ -0,0 +1,63 @@
+/*
+ * 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.hopgui.perspective.explorer.file;
+
+import org.apache.hop.ui.hopgui.file.IHopFileType;
+
+public class FileDetails {
+ private String path;
+ private IHopFileType hopFileType;
+
+ public FileDetails( String path, IHopFileType hopFileType ) {
+ this.path = path;
+ this.hopFileType = hopFileType;
+ }
+
+ /**
+ * Gets path
+ *
+ * @return value of path
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * @param path The path to set
+ */
+ public void setPath( String path ) {
+ this.path = path;
+ }
+
+ /**
+ * Gets hopFileType
+ *
+ * @return value of hopFileType
+ */
+ public IHopFileType getHopFileType() {
+ return hopFileType;
+ }
+
+ /**
+ * @param hopFileType The hopFileType to set
+ */
+ public void setHopFileType( IHopFileType hopFileType ) {
+ this.hopFileType = hopFileType;
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/IExplorerFileType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/IExplorerFileType.java
new file mode 100644
index 0000000..70dc227
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/IExplorerFileType.java
@@ -0,0 +1,37 @@
+/*
+ * 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.hopgui.perspective.explorer.file;
+
+import org.apache.hop.ui.hopgui.HopGui;
+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;
+
+public interface IExplorerFileType<T extends IExplorerFileTypeHandler> extends IHopFileType {
+
+ /**
+ * Create a new file type handler for the given Hop GUI instance, perspective and file
+ *
+ * @param hopGui The Hop GUI
+ * @param perspective The perspective
+ * @param file The file
+ * @return
+ */
+ T createFileTypeHandler(HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file);
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/IExplorerFileTypeHandler.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/IExplorerFileTypeHandler.java
new file mode 100644
index 0000000..2ca3b94
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/IExplorerFileTypeHandler.java
@@ -0,0 +1,33 @@
+/*
+ * 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.hopgui.perspective.explorer.file;
+
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerFile;
+import org.eclipse.swt.widgets.Composite;
+
+public interface IExplorerFileTypeHandler extends IHopFileTypeHandler {
+ /**
+ * Render a file on a composite
+ *
+ * @param composite The parent composite in a new tab in the explorer perspective
+ */
+ void renderFile( Composite composite);
+
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/capabilities/FileTypeCapabilities.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/capabilities/FileTypeCapabilities.java
new file mode 100644
index 0000000..cc984e3
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/capabilities/FileTypeCapabilities.java
@@ -0,0 +1,31 @@
+/*
+ * 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.hopgui.perspective.explorer.file.capabilities;
+
+import java.util.Properties;
+
+public class FileTypeCapabilities {
+ public static final Properties getCapabilities(String...capabilities) {
+ Properties properties = new Properties();
+ for (String capability : capabilities) {
+ properties.put(capability, "true");
+ }
+ return properties;
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/FolderFileType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/FolderFileType.java
new file mode 100644
index 0000000..2196fa6
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/FolderFileType.java
@@ -0,0 +1,116 @@
+/*
+ * 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.hopgui.perspective.explorer.file.types;
+
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.file.IHasFilename;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.core.vfs.HopVfs;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.context.IGuiContextHandler;
+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 java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+@HopFileTypePlugin(
+ id = "FolderFileType",
+ name = "Folder File Type",
+ description = "Folder handling in the explorer perspective",
+ image = "ui/images/folder.svg")
+
+public class FolderFileType implements IHopFileType {
+ @Override
+ public String getName() {
+ return "folder";
+ }
+
+ @Override
+ public String getDefaultFileExtension() {
+ return "";
+ }
+
+ @Override
+ public String[] getFilterExtensions() {
+ return new String[0];
+ }
+
+ @Override
+ public String[] getFilterNames() {
+ return new String[0];
+ }
+
+ @Override
+ public Properties getCapabilities() {
+ return new Properties();
+ }
+
+ @Override
+ public boolean hasCapability(String capability) {
+ return false;
+ }
+
+ @Override
+ public IHopFileTypeHandler openFile(
+ HopGui hopGui, String filename, IVariables parentVariableSpace) throws HopException {
+ return new EmptyHopFileTypeHandler();
+ }
+
+ @Override
+ public IHopFileTypeHandler newFile(HopGui hopGui, IVariables parentVariableSpace)
+ throws HopException {
+ return new EmptyHopFileTypeHandler();
+ }
+
+ /**
+ * See if this is a folder
+ *
+ * @param filename The filename
+ * @param checkContent True if we want to look inside the file content
+ * @return
+ * @throws HopException
+ */
+ @Override
+ public boolean isHandledBy(String filename, boolean checkContent) throws HopException {
+ try {
+ return HopVfs.getFileObject(filename).isFolder();
+ } catch (Exception e) {
+ throw new HopException("Error seeing if file '" + filename + "' is a folder", e);
+ }
+ }
+
+ @Override
+ public boolean supportsFile(IHasFilename metaObject) {
+ return false;
+ }
+
+ @Override
+ public List<IGuiContextHandler> getContextHandlers() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public String getFileTypeImage() {
+ return getClass().getAnnotation(HopFileTypePlugin.class).image();
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/GenericFileType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/GenericFileType.java
new file mode 100644
index 0000000..5003fe3
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/GenericFileType.java
@@ -0,0 +1,111 @@
+/*
+ * 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.hopgui.perspective.explorer.file.types;
+
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.file.IHasFilename;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.core.vfs.HopVfs;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.context.IGuiContextHandler;
+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 java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+// TODO: implement as plugin, move to text transform plugin
+//
+public class GenericFileType implements IHopFileType {
+ @Override
+ public String getName() {
+ return "Generic File";
+ }
+
+ @Override
+ public String getDefaultFileExtension() {
+ return "";
+ }
+
+ @Override
+ public String[] getFilterExtensions() {
+ return new String[0];
+ }
+
+ @Override
+ public String[] getFilterNames() {
+ return new String[0];
+ }
+
+ @Override
+ public Properties getCapabilities() {
+ return new Properties();
+ }
+
+ @Override
+ public boolean hasCapability(String capability) {
+ return false;
+ }
+
+ @Override
+ public IHopFileTypeHandler openFile(
+ HopGui hopGui, String filename, IVariables parentVariableSpace) throws HopException {
+ return new EmptyHopFileTypeHandler();
+ }
+
+ @Override
+ public IHopFileTypeHandler newFile(HopGui hopGui, IVariables parentVariableSpace)
+ throws HopException {
+ return new EmptyHopFileTypeHandler();
+ }
+
+ /**
+ * See if this is a generic file
+ *
+ * @param filename The filename
+ * @param checkContent True if we want to look inside the file content
+ * @return
+ * @throws HopException
+ */
+ @Override
+ public boolean isHandledBy(String filename, boolean checkContent) throws HopException {
+ try {
+ return HopVfs.getFileObject(filename).isFile();
+ } catch (Exception e) {
+ throw new HopException("Error seeing if file '" + filename + "' is a generic file", e);
+ }
+ }
+
+ @Override
+ public boolean supportsFile(IHasFilename metaObject) {
+ return false;
+ }
+
+ @Override
+ public List<IGuiContextHandler> getContextHandlers() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public String getFileTypeImage() {
+ return "ui/images/file.svg";
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/base/BaseExplorerFileType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/base/BaseExplorerFileType.java
new file mode 100644
index 0000000..d085fd8
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/base/BaseExplorerFileType.java
@@ -0,0 +1,188 @@
+/*
+ * 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.hopgui.perspective.explorer.file.types.base;
+
+import org.apache.commons.vfs2.FileObject;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.file.IHasFilename;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.core.vfs.HopVfs;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.context.IGuiContextHandler;
+import org.apache.hop.ui.hopgui.file.HopFileTypeBase;
+import org.apache.hop.ui.hopgui.file.HopFileTypePlugin;
+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;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.IExplorerFileTypeHandler;
+import org.eclipse.swt.custom.CTabItem;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+public abstract class BaseExplorerFileType<T extends IExplorerFileTypeHandler>
+ extends HopFileTypeBase implements IExplorerFileType<T> {
+
+ private String name;
+ private String defaultFileExtension;
+ private String[] filterExtensions;
+ private String[] filterNames;
+ private Properties capabilities;
+
+ public BaseExplorerFileType() {}
+
+ public BaseExplorerFileType(
+ String name,
+ String defaultFileExtension,
+ String[] filterExtensions,
+ String[] filterNames,
+ Properties capabilities) {
+ this.name = name;
+ this.defaultFileExtension = defaultFileExtension;
+ this.filterExtensions = filterExtensions;
+ this.filterNames = filterNames;
+ this.capabilities = capabilities;
+ }
+
+ @Override
+ public boolean supportsFile(IHasFilename metaObject) {
+ return false;
+ }
+
+ @Override
+ public List<IGuiContextHandler> getContextHandlers() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Gets name
+ *
+ * @return value of name
+ */
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ /** @param name The name to set */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Gets defaultFileExtension
+ *
+ * @return value of defaultFileExtension
+ */
+ @Override
+ public String getDefaultFileExtension() {
+ return defaultFileExtension;
+ }
+
+ /** @param defaultFileExtension The defaultFileExtension to set */
+ public void setDefaultFileExtension(String defaultFileExtension) {
+ this.defaultFileExtension = defaultFileExtension;
+ }
+
+ /**
+ * Gets filterExtensions
+ *
+ * @return value of filterExtensions
+ */
+ @Override
+ public String[] getFilterExtensions() {
+ return filterExtensions;
+ }
+
+ /** @param filterExtensions The filterExtensions to set */
+ public void setFilterExtensions(String[] filterExtensions) {
+ this.filterExtensions = filterExtensions;
+ }
+
+ /**
+ * Gets filterNames
+ *
+ * @return value of filterNames
+ */
+ @Override
+ public String[] getFilterNames() {
+ return filterNames;
+ }
+
+ /** @param filterNames The filterNames to set */
+ public void setFilterNames(String[] filterNames) {
+ this.filterNames = filterNames;
+ }
+
+ /**
+ * Gets capabilities
+ *
+ * @return value of capabilities
+ */
+ @Override
+ public Properties getCapabilities() {
+ return capabilities;
+ }
+
+ /** @param capabilities The capabilities to set */
+ public void setCapabilities(Properties capabilities) {
+ this.capabilities = capabilities;
+ }
+
+ @Override
+ public String getFileTypeImage() {
+ return getClass().getAnnotation(HopFileTypePlugin.class).image();
+ }
+
+ @Override
+ public T openFile(HopGui hopGui, String filename, IVariables parentVariables)
+ throws HopException {
+
+ try {
+ FileObject fileObject = HopVfs.getFileObject(parentVariables.resolve(filename));
+ String name = fileObject.getName().getBaseName();
+
+ // Open the file in the explorer perspective
+ //
+ ExplorerPerspective perspective = ExplorerPerspective.getInstance();
+
+ ExplorerFile explorerFile = new ExplorerFile();
+ explorerFile.setName(name);
+ explorerFile.setFilename(filename);
+ explorerFile.setFileType(this);
+ explorerFile.setTabImage(perspective.getFileTypeImage(this));
+
+ T fileTypeHandler = createFileTypeHandler(hopGui, perspective, explorerFile);
+ explorerFile.setFileTypeHandler(fileTypeHandler);
+
+ CTabItem tabItem = perspective.addFile(explorerFile, fileTypeHandler);
+ explorerFile.setName(tabItem.getText());
+
+ return fileTypeHandler;
+ } catch (Exception e) {
+ throw new HopException(
+ "Error opening file '" + filename + "' in a new tab in the Explorer perspective", e);
+ }
+ }
+
+ @Override
+ public abstract T createFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file);
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/base/BaseExplorerFileTypeHandler.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/base/BaseExplorerFileTypeHandler.java
new file mode 100644
index 0000000..e9463cc
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/base/BaseExplorerFileTypeHandler.java
@@ -0,0 +1,246 @@
+/*
+ * 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.hopgui.perspective.explorer.file.types.base;
+
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.ui.core.dialog.ErrorDialog;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.context.IGuiContextHandler;
+import org.apache.hop.ui.hopgui.file.IHopFileType;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerFile;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.MessageBox;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public abstract class BaseExplorerFileTypeHandler implements IHopFileTypeHandler {
+
+ protected HopGui hopGui;
+ protected ExplorerPerspective perspective;
+ protected ExplorerFile explorerFile;
+
+ public BaseExplorerFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile explorerFile) {
+ this.hopGui = hopGui;
+ this.perspective = perspective;
+ this.explorerFile = explorerFile;
+ }
+
+ @Override
+ public List<IGuiContextHandler> getContextHandlers() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Object getSubject() {
+ return explorerFile;
+ }
+
+ @Override
+ public String getName() {
+ return explorerFile.getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ explorerFile.setName(name);
+ }
+
+ @Override
+ public IHopFileType getFileType() {
+ return explorerFile.getFileType();
+ }
+
+ @Override
+ public String getFilename() {
+ return explorerFile.getFilename();
+ }
+
+ @Override
+ public void setFilename(String filename) {
+ explorerFile.setFilename(filename);
+ }
+
+ @Override
+ public void save() throws HopException {
+ throw new HopException("Saving file '" + getFilename() + " is not implemented.");
+ }
+
+ @Override
+ public void saveAs(String filename) throws HopException {
+ throw new HopException("Saving file '" + getFilename() + " is not implemented.");
+ }
+
+ @Override
+ public void start() {
+ // Nothing to start
+ }
+
+ @Override
+ public void stop() {
+ // Nothing to stop
+ }
+
+ @Override
+ public void pause() {
+ // Nothing to pause
+ }
+
+ @Override
+ public void resume() {
+ // Nothing to resume
+ }
+
+ @Override
+ public void preview() {
+ // Nothing to preview
+ }
+
+ @Override
+ public void debug() {
+ // Nothing to debug
+ }
+
+ @Override
+ public void redraw() {}
+
+ @Override
+ public void updateGui() {}
+
+ @Override
+ public void selectAll() {}
+
+ @Override
+ public void unselectAll() {}
+
+ @Override
+ public void copySelectedToClipboard() {}
+
+ @Override
+ public void cutSelectedToClipboard() {}
+
+ @Override
+ public void deleteSelected() {}
+
+ @Override
+ public void pasteFromClipboard() {}
+
+ @Override
+ public boolean isCloseable() {
+ try {
+ if (explorerFile.isChanged()) {
+ MessageBox messageDialog =
+ new MessageBox(hopGui.getShell(), SWT.ICON_QUESTION | SWT.YES | SWT.NO | SWT.CANCEL);
+ messageDialog.setText("Save file?");
+ messageDialog.setMessage(
+ "Do you want to save file '" + explorerFile.getName() + "' before closing?");
+ int answer = messageDialog.open();
+ if ((answer & SWT.YES) != 0) {
+ save();
+ return true;
+ }
+ if ((answer & SWT.NO) != 0) {
+ // User doesn't want to save but close
+ return true;
+ }
+ return false;
+ }
+ return true;
+ } catch (Exception e) {
+ new ErrorDialog(hopGui.getShell(), "Error", "Error preparing file close of '"+explorerFile.getName()+"'", e);
+ return false;
+ }
+ }
+
+ @Override
+ public boolean hasChanged() {
+ return false;
+ }
+
+ @Override
+ public void undo() {}
+
+ @Override
+ public void redo() {}
+
+ @Override
+ public Map<String, Object> getStateProperties() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public void close() {
+ perspective.closeFile(explorerFile);
+ }
+
+ @Override
+ public void applyStateProperties(Map<String, Object> stateProperties) {}
+
+ @Override
+ public IVariables getVariables() {
+ return hopGui.getVariables();
+ }
+
+ /**
+ * Gets hopGui
+ *
+ * @return value of hopGui
+ */
+ public HopGui getHopGui() {
+ return hopGui;
+ }
+
+ /** @param hopGui The hopGui to set */
+ public void setHopGui(HopGui hopGui) {
+ this.hopGui = hopGui;
+ }
+
+ /**
+ * Gets perspective
+ *
+ * @return value of perspective
+ */
+ public ExplorerPerspective getPerspective() {
+ return perspective;
+ }
+
+ /** @param perspective The perspective to set */
+ public void setPerspective(ExplorerPerspective perspective) {
+ this.perspective = perspective;
+ }
+
+ /**
+ * Gets explorerFile
+ *
+ * @return value of explorerFile
+ */
+ public ExplorerFile getExplorerFile() {
+ return explorerFile;
+ }
+
+ /** @param explorerFile The explorerFile to set */
+ public void setExplorerFile(ExplorerFile explorerFile) {
+ this.explorerFile = explorerFile;
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/log/LogExplorerFileType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/log/LogExplorerFileType.java
new file mode 100644
index 0000000..2cfdea5
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/log/LogExplorerFileType.java
@@ -0,0 +1,69 @@
+/*
+ * 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.hopgui.perspective.explorer.file.types.log;
+
+import org.apache.hop.core.Props;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.HopFileTypePlugin;
+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.IExplorerFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileType;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.Properties;
+
+@HopFileTypePlugin(
+ id = "LogExplorerFileType",
+ name = "LOG File Type",
+ description = "Log file handling in the explorer perspective",
+ image = "ui/images/log.svg")
+public class LogExplorerFileType extends BaseExplorerFileType<LogExplorerFileTypeHandler>
+ implements IExplorerFileType<LogExplorerFileTypeHandler> {
+
+ public LogExplorerFileType() {
+ super("Log File", ".log", new String[] {"*.log"}, new String[] {"Log files"}, new Properties());
+ }
+
+ @Override
+ public LogExplorerFileTypeHandler createFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file) {
+ return new LogExplorerFileTypeHandler(hopGui, perspective, file);
+ }
+
+ @Override
+ public IHopFileTypeHandler newFile(HopGui hopGui, IVariables parentVariableSpace)
+ throws HopException {
+ // Not implemented
+ return new EmptyHopFileTypeHandler();
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/log/LogExplorerFileTypeHandler.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/log/LogExplorerFileTypeHandler.java
new file mode 100644
index 0000000..25ab682
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/log/LogExplorerFileTypeHandler.java
@@ -0,0 +1,83 @@
+/*
+ * 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.hopgui.perspective.explorer.file.types.log;
+
+import org.apache.hop.core.Props;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+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.IExplorerFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileTypeHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+/**
+ * How do we handle a log file in file explorer perspective?
+ */
+public class LogExplorerFileTypeHandler extends BaseExplorerFileTypeHandler implements IExplorerFileTypeHandler {
+
+ private Text wText;
+
+ public LogExplorerFileTypeHandler( HopGui hopGui, ExplorerPerspective perspective, ExplorerFile explorerFile ) {
+ super( hopGui, perspective, explorerFile );
+ }
+
+ @Override
+ public void renderFile(Composite composite) {
+ // Render the file by simply showing the file content as a text widget...
+ //
+ wText = new Text(composite, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ PropsUi.getInstance().setLook(wText, Props.WIDGET_STYLE_FIXED);
+ wText.setEditable( false );
+ FormData fdText = new FormData();
+ fdText.left = new FormAttachment(0, 0);
+ fdText.right = new FormAttachment(100, 0);
+ fdText.top = new FormAttachment(0, 0);
+ fdText.bottom = new FormAttachment(100, 0);
+ wText.setLayoutData(fdText);
+
+ // TODO: add bottom section to show status, size, cursor position...
+ // TODO: add a checkbox so that we can implement a "tail -f" log viewer
+ //
+
+ // Load the content of the JSON file...
+ //
+ File file = new File(explorerFile.getFilename());
+ if (file.exists()) {
+ try {
+ String contents = new String( Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
+ wText.setText(contents);
+ } catch (Exception e) {
+ LogChannel.UI.logError(
+ "Error reading contents of file '" + explorerFile.getFilename() + "'", e);
+ }
+ }
+ }
+
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/svg/SvgExplorerFileType.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/svg/SvgExplorerFileType.java
new file mode 100644
index 0000000..62493a8
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/svg/SvgExplorerFileType.java
@@ -0,0 +1,71 @@
+/*
+ * 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.hopgui.perspective.explorer.file.types.svg;
+
+import org.apache.hop.core.SwtUniversalImageSvg;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.core.svg.SvgCache;
+import org.apache.hop.core.svg.SvgCacheEntry;
+import org.apache.hop.core.svg.SvgFile;
+import org.apache.hop.core.svg.SvgImage;
+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.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.IExplorerFileType;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileType;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+
+import java.util.Properties;
+
+@HopFileTypePlugin(
+ id = "SvgExplorerFileType",
+ name = "SVG File Type",
+ description = "SVG file handling in the explorer perspective",
+ image = "ui/images/image.svg")
+public class SvgExplorerFileType extends BaseExplorerFileType<SvgExplorerFileTypeHandler>
+ implements IExplorerFileType<SvgExplorerFileTypeHandler> {
+
+ public SvgExplorerFileType() {
+ super("SVG file", ".svg", new String[] {"*.svg"}, new String[] {"SVG Files"}, new Properties());
+ }
+
+ @Override
+ public SvgExplorerFileTypeHandler createFileTypeHandler(
+ HopGui hopGui, ExplorerPerspective perspective, ExplorerFile file) {
+ return new SvgExplorerFileTypeHandler(hopGui, perspective, file);
+ }
+
+ @Override
+ public IHopFileTypeHandler newFile(HopGui hopGui, IVariables parentVariableSpace)
+ throws HopException {
+ return new EmptyHopFileTypeHandler();
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/svg/SvgExplorerFileTypeHandler.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/svg/SvgExplorerFileTypeHandler.java
new file mode 100644
index 0000000..c4cb361
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/file/types/svg/SvgExplorerFileTypeHandler.java
@@ -0,0 +1,92 @@
+/*
+ * 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.hopgui.perspective.explorer.file.types.svg;
+
+import org.apache.hop.core.SwtUniversalImageSvg;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.core.svg.SvgCache;
+import org.apache.hop.core.svg.SvgCacheEntry;
+import org.apache.hop.core.svg.SvgFile;
+import org.apache.hop.core.svg.SvgImage;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
+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.IExplorerFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.explorer.file.types.base.BaseExplorerFileTypeHandler;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * How do we handle an SVG file in file explorer perspective?
+ */
+public class SvgExplorerFileTypeHandler extends BaseExplorerFileTypeHandler implements IExplorerFileTypeHandler {
+
+ public SvgExplorerFileTypeHandler( HopGui hopGui, ExplorerPerspective perspective, ExplorerFile explorerFile ) {
+ super( hopGui, perspective, explorerFile );
+ }
+
+ private static void paintControl( PaintEvent event, ExplorerFile explorerFile, Canvas canvas) {
+ // Render the SVG file...
+ //
+ Rectangle area = canvas.getBounds();
+
+ try {
+ SvgCacheEntry entry =
+ SvgCache.loadSvg(
+ new SvgFile(explorerFile.getFilename(), SvgExplorerFileType.class.getClassLoader()));
+ SwtUniversalImageSvg svg = new SwtUniversalImageSvg(new SvgImage(entry.getSvgDocument()), true);
+
+ float factorX = (float)area.width / entry.getWidth();
+ float factorY = (float)area.height / entry.getHeight();
+ float minFactor = Math.min(factorX, factorY);
+
+ int imageWidth = (int)(entry.getWidth()*minFactor);
+ int imageHeight = (int)(entry.getHeight()*minFactor);
+
+ Image image = svg.getAsBitmapForSize(canvas.getDisplay(), imageWidth, imageHeight);
+
+ event.gc.drawImage(image, 0, 0);
+ } catch (Exception e) {
+ LogChannel.GENERAL.logError("Error rendering SVG", e);
+ }
+ }
+
+ // Render the SVG file...
+ //
+ @Override
+ public void renderFile(Composite composite) {
+ final Canvas wCanvas = new Canvas(composite, SWT.NONE);
+ FormData fdCanvas = new FormData();
+ fdCanvas.left = new FormAttachment(0, 0);
+ fdCanvas.right = new FormAttachment(100, 0);
+ fdCanvas.top = new FormAttachment(0, 0);
+ fdCanvas.bottom = new FormAttachment(100, 0);
+ wCanvas.setLayoutData(fdCanvas);
+
+ wCanvas.addPaintListener(e -> paintControl(e, explorerFile, wCanvas));
+ }
+
+}