diff --git a/core/src/main/java/org/apache/hop/metadata/api/HopMetadata.java b/core/src/main/java/org/apache/hop/metadata/api/HopMetadata.java index 5e638f48506..713c806f56c 100644 --- a/core/src/main/java/org/apache/hop/metadata/api/HopMetadata.java +++ b/core/src/main/java/org/apache/hop/metadata/api/HopMetadata.java @@ -51,12 +51,4 @@ * @return the type of metadata this property represents. */ HopMetadataPropertyType hopMetadataPropertyType() default HopMetadataPropertyType.NONE; - - /** - * A boolean flag, represented as a string, which tells whether the given HopMetadata - * implementation has to be shown into a tree of folders - * - * @return a boolean as string flag that will enable the UI to allow folders creation - */ - String subfoldersEnabled() default "false"; } diff --git a/core/src/main/java/org/apache/hop/metadata/api/HopMetadataBase.java b/core/src/main/java/org/apache/hop/metadata/api/HopMetadataBase.java index cceea1fb41e..e99b1ecbc3d 100644 --- a/core/src/main/java/org/apache/hop/metadata/api/HopMetadataBase.java +++ b/core/src/main/java/org/apache/hop/metadata/api/HopMetadataBase.java @@ -22,11 +22,12 @@ public class HopMetadataBase implements IHopMetadata { - @HopMetadataProperty protected String path; - /** All metadata objects have a name to uniquely identify it. */ @HopMetadataProperty protected String name; + /** All metadata objects can have a virtual path to organize them */ + @HopMetadataProperty protected String virtualPath; + /** * The metadata provider name is optionally used at runtime to figure out where the metadata came * from. Optionally used by plugins. It's volatile because it's never persisted. @@ -38,13 +39,13 @@ public HopMetadataBase() {} public HopMetadataBase(String name) { this(); this.name = name; - this.path = ""; + this.virtualPath = ""; } - public HopMetadataBase(String name, String path) { + public HopMetadataBase(String name, String virtualPath) { this(); this.name = name; - this.path = path; + this.virtualPath = virtualPath; } @Override @@ -106,26 +107,40 @@ public void setMetadataProviderName(String metadataProviderName) { this.metadataProviderName = metadataProviderName; } + /** + * Get the virtual path set on a metadata item + * + * @return a String representing the virtual path + */ @Override - public String getPath() { - return path; + public String getVirtualPath() { + return virtualPath; } + /** + * Set the virtual path on a metadata item + * + * @param virtualPath the virtual path to set to the metadata item + */ @Override - public void setPath(String path) { - this.path = path; + public void setVirtualPath(String virtualPath) { + this.virtualPath = virtualPath; } + /** + * Return the virtual path and name of the object + * + * @return the virtual path and name of the object + */ @Override public String getFullName() { - if (path == null || path.isBlank()) { + if (virtualPath == null || virtualPath.isEmpty()) { return name; + } + if (virtualPath.endsWith("/")) { + return virtualPath + name; } else { - if (path.endsWith("/")) { - return path + name; - } else { - return path + "/" + name; - } + return virtualPath + "/" + name; } } } diff --git a/core/src/main/java/org/apache/hop/metadata/api/IHopMetadata.java b/core/src/main/java/org/apache/hop/metadata/api/IHopMetadata.java index d34d7b9448a..6e371c6a534 100644 --- a/core/src/main/java/org/apache/hop/metadata/api/IHopMetadata.java +++ b/core/src/main/java/org/apache/hop/metadata/api/IHopMetadata.java @@ -53,9 +53,22 @@ public interface IHopMetadata { */ void setMetadataProviderName(String metadataProviderName); - String getPath(); + /** + * @return the virtual path for organizing metadata items + */ + String getVirtualPath(); - void setPath(String path); + /** + * Set the virtual path on a metadata item + * + * @param virtualPath the virtual path to set to the metadata item + */ + void setVirtualPath(String virtualPath); + /** + * Get the complete name of the object (virtual path + name) + * + * @return the full name of the object + */ String getFullName(); } diff --git a/core/src/main/java/org/apache/hop/metadata/api/IHopMetadataSerializer.java b/core/src/main/java/org/apache/hop/metadata/api/IHopMetadataSerializer.java index 121842ca19f..f8e3560b518 100644 --- a/core/src/main/java/org/apache/hop/metadata/api/IHopMetadataSerializer.java +++ b/core/src/main/java/org/apache/hop/metadata/api/IHopMetadataSerializer.java @@ -19,7 +19,6 @@ import java.util.List; import org.apache.hop.core.exception.HopException; -import org.apache.hop.metadata.serializer.FileSystemNode; /** * This metadata interface describes how an object T can be serialized and analyzed. @@ -68,11 +67,6 @@ public interface IHopMetadataSerializer { */ List listObjectNames() throws HopException; - default FileSystemNode getFileSystemTree() throws HopException { - throw new UnsupportedOperationException( - "listObjectNames(String folderName, Boolean recursive) is not supported by this metadata serializer"); - } - /** * See if an object with the given name exists. * diff --git a/core/src/main/java/org/apache/hop/metadata/serializer/FileSystemNode.java b/core/src/main/java/org/apache/hop/metadata/serializer/FileSystemNode.java deleted file mode 100644 index b4a3bb86dc1..00000000000 --- a/core/src/main/java/org/apache/hop/metadata/serializer/FileSystemNode.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.hop.metadata.serializer; - -import java.util.ArrayList; -import java.util.List; - -// Represents a node in the file system tree -public class FileSystemNode { - private String name; // Name of the file or folder - private String path; // Absolute path to the file or folder - private Type type; // Type (file or folder) - private FileSystemNode parent; // Parent node - private List children; // Children nodes (only for folder) - - // Enum for node type - public enum Type { - FILE, - FOLDER - } - - // Constructor - - public FileSystemNode(String name, String path, Type type, FileSystemNode parent) { - this.name = name; - this.path = path; - this.type = type; - this.parent = parent; - this.children = new ArrayList<>(); - - if (this.parent != null) { - this.parent.addChild(this); - } - } - - // Add a child node - - public void addChild(FileSystemNode child) { - if (this.type == Type.FOLDER) { - this.children.add(child); - } - } - - // Getters - - public String getName() { - return name; - } - - public String getPath() { - return path; - } - - public Type getType() { - return type; - } - - public FileSystemNode getParent() { - return parent; - } - - public List getChildren() { - return children; - } - - public boolean isFolder() { - return type == Type.FOLDER; - } - - public boolean isFile() { - return type == Type.FILE; - } -} diff --git a/core/src/main/java/org/apache/hop/metadata/serializer/json/JsonMetadataSerializer.java b/core/src/main/java/org/apache/hop/metadata/serializer/json/JsonMetadataSerializer.java index dd46ee00635..aa74fa4f415 100644 --- a/core/src/main/java/org/apache/hop/metadata/serializer/json/JsonMetadataSerializer.java +++ b/core/src/main/java/org/apache/hop/metadata/serializer/json/JsonMetadataSerializer.java @@ -27,7 +27,6 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import org.apache.commons.lang.StringUtils; @@ -40,7 +39,6 @@ import org.apache.hop.metadata.api.IHopMetadata; import org.apache.hop.metadata.api.IHopMetadataProvider; import org.apache.hop.metadata.api.IHopMetadataSerializer; -import org.apache.hop.metadata.serializer.FileSystemNode; import org.json.simple.JSONObject; /** @@ -142,11 +140,11 @@ private void inheritVariables(T t) { @Override public void save(T t) throws HopException { - if (StringUtils.isEmpty(t.getFullName())) { + if (StringUtils.isEmpty(t.getName())) { throw new HopException("Error: To save a metadata object it needs to have a name"); } - String filename = calculateFilename(t); + String filename = calculateFilename(t.getName()); try { JSONObject jObject = parser.getJsonObject(t); @@ -172,63 +170,29 @@ public void save(T t) throws HopException { } } - public String calculateFilename(T t) { - String prefix = t.getPath() == null ? baseFolder : t.getPath(); - if (!prefix.endsWith("/")) { - prefix += "/"; - } - return prefix + t.getName() + ".json"; - } - public String calculateFilename(String name) { - if (name.startsWith(baseFolder)) { - return name; - } return baseFolder + "/" + name + ".json"; } - public String calculateFolderName(String name) { - if (name.startsWith(baseFolder)) { - return name; - } - return baseFolder + "/" + name; - } - @Override public T delete(String name) throws HopException { if (name == null) { throw new HopException( "Error: you need to specify the name of the metadata object to delete"); } - boolean exists = exists(name); - if (!exists) { + if (!exists(name)) { throw new HopException("Error: Object '" + name + "' doesn't exist"); } - - T t = null; - String objectName = null; - if (existsFolder(name)) { - objectName = calculateFolderName(name); - } - if (existsFile(name)) { - t = load(name); - objectName = calculateFilename(name); - } - + T t = load(name); + String filename = calculateFilename(name); try { - var object = HopVfs.getFileObject(objectName); - boolean deleted = false; - if (object.isFolder()) { - deleted = object.deleteAll() > 0; - } else { - deleted = object.delete(); - } + boolean deleted = HopVfs.getFileObject(filename).delete(); if (!deleted) { throw new HopException( - "Error: Object '" + name + "' could not be deleted, name : " + objectName); + "Error: Object '" + name + "' could not be deleted, filename : " + filename); } } catch (FileSystemException e) { - throw new HopException("Error deleting Object '" + name + "' with name : " + objectName); + throw new HopException("Error deleting Object '" + name + "' with filename : " + filename); } return t; } @@ -250,77 +214,9 @@ public List listObjectNames() throws HopException { } } - @Override - public FileSystemNode getFileSystemTree() throws HopException { - FileObject currentItem = HopVfs.getFileObject(baseFolder); - FileSystemNode root = - new FileSystemNode( - currentItem.getName().getBaseName(), - currentItem.getName().getPath(), - FileSystemNode.Type.FOLDER, - null); - return getFileSystemTree(root); - } - - private FileSystemNode getFileSystemTree(FileSystemNode parent) throws HopException { - FileObject currentItem = HopVfs.getFileObject(parent.getPath()); - try { - Arrays.asList(currentItem.getChildren()).stream() - .forEach( - f -> { - try { - if (f.isFolder()) { - FileSystemNode currentFolder = - new FileSystemNode( - f.getName().getBaseName(), - f.getName().getPath(), - FileSystemNode.Type.FOLDER, - parent); - getFileSystemTree(currentFolder); // Recursive call for the folder - } else { - if (f.getName().getExtension().equals("json")) { - FileSystemNode currentFile = - new FileSystemNode( - f.getName().getBaseName().replaceAll("\\.json$", ""), - f.getName().getPath(), - FileSystemNode.Type.FILE, - parent); - } - } - } catch (FileSystemException | HopException e) { - throw new RuntimeException(e); - } - }); - } catch (Exception e) { - throw new HopException("Error searching for JSON files", e); - } - return parent; - } - - // try { - // List jsonFiles = HopVfs.findFiles(folder, "json", false); - // List names = new ArrayList<>(); - // for (FileObject jsonFile : jsonFiles) { - // String baseName = jsonFile.getName().getBaseName(); - // names.add(baseName.replaceAll("\\.json$", "")); - // } - // return names; - // } catch (Exception e) { - // throw new HopException("Error searching for JSON files", e); - // } @Override public boolean exists(String name) throws HopException { - return existsFolder(name) || existsFile(name); - } - - private boolean existsFile(String name) throws HopException { - - return !existsFolder(name) - && (HopVfs.fileExists(name) || HopVfs.fileExists(calculateFilename(name))); - } - - private boolean existsFolder(String name) throws HopException { - return HopVfs.fileExists(name) || HopVfs.fileExists(calculateFolderName(name)); + return HopVfs.fileExists(calculateFilename(name)); } /** diff --git a/core/src/main/java/org/apache/hop/metadata/serializer/multi/MultiMetadataSerializer.java b/core/src/main/java/org/apache/hop/metadata/serializer/multi/MultiMetadataSerializer.java index 3072c664558..635c2f84d21 100644 --- a/core/src/main/java/org/apache/hop/metadata/serializer/multi/MultiMetadataSerializer.java +++ b/core/src/main/java/org/apache/hop/metadata/serializer/multi/MultiMetadataSerializer.java @@ -29,7 +29,6 @@ import org.apache.hop.metadata.api.IHopMetadata; import org.apache.hop.metadata.api.IHopMetadataProvider; import org.apache.hop.metadata.api.IHopMetadataSerializer; -import org.apache.hop.metadata.serializer.FileSystemNode; public class MultiMetadataSerializer implements IHopMetadataSerializer { @@ -142,15 +141,6 @@ public List listObjectNames() throws HopException { return new ArrayList<>(set); } - @Override - public FileSystemNode getFileSystemTree() throws HopException { - FileSystemNode root = new FileSystemNode("root", "/", FileSystemNode.Type.FOLDER, null); - for (IHopMetadataProvider provider : multiProvider.getProviders()) { - root.addChild(provider.getSerializer(managedClass).getFileSystemTree()); - } - return root; - } - @Override public boolean exists(String name) throws HopException { for (IHopMetadataProvider provider : multiProvider.getProviders()) { diff --git a/core/src/test/java/org/apache/hop/metadata/serializer/json/JsonMetadataSerializerTest.java b/core/src/test/java/org/apache/hop/metadata/serializer/json/JsonMetadataSerializerTest.java index 78144a87170..4b76b3baff6 100644 --- a/core/src/test/java/org/apache/hop/metadata/serializer/json/JsonMetadataSerializerTest.java +++ b/core/src/test/java/org/apache/hop/metadata/serializer/json/JsonMetadataSerializerTest.java @@ -41,11 +41,10 @@ public class JsonMetadataSerializerTest extends TestCase { @Override protected void setUp() throws Exception { - String tmpDir = System.getProperty("java.io.tmpdir"); - if (!tmpDir.endsWith(Const.FILE_SEPARATOR)) { - tmpDir += Const.FILE_SEPARATOR; - } - String baseFolder = tmpDir + "metadata"; // UUID.randomUUID(); + String baseFolder = + System.getProperty("java.io.tmpdir") + + Const.FILE_SEPARATOR + + "metadata"; // UUID.randomUUID(); metadataProvider = new JsonMetadataProvider( new HopTwoWayPasswordEncoder(), baseFolder, Variables.getADefaultVariableSpace()); diff --git a/plugins/misc/static-schema/src/main/java/org/apache/hop/staticschema/metadata/SchemaDefinition.java b/plugins/misc/static-schema/src/main/java/org/apache/hop/staticschema/metadata/SchemaDefinition.java index 17fadc76326..19c44abcb31 100644 --- a/plugins/misc/static-schema/src/main/java/org/apache/hop/staticschema/metadata/SchemaDefinition.java +++ b/plugins/misc/static-schema/src/main/java/org/apache/hop/staticschema/metadata/SchemaDefinition.java @@ -38,8 +38,7 @@ description = "i18n::SchemaDefinition.Description", image = "ui/images/folder.svg", documentationUrl = "/metadata-types/static-schema-definition.html", - hopMetadataPropertyType = HopMetadataPropertyType.STATIC_SCHEMA_DEFINITION, - subfoldersEnabled = "true") + hopMetadataPropertyType = HopMetadataPropertyType.STATIC_SCHEMA_DEFINITION) public class SchemaDefinition extends HopMetadataBase implements Serializable, IHopMetadata { private static final Class PKG = SchemaDefinition.class; diff --git a/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelinput/ExcelInputDialog.java b/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelinput/ExcelInputDialog.java index ddf086842ec..d18602df4a2 100644 --- a/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelinput/ExcelInputDialog.java +++ b/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelinput/ExcelInputDialog.java @@ -888,7 +888,7 @@ public void widgetSelected(SelectionEvent e) { wSchemaDefinition.setLayoutData(fdSchemaDefinition); try { - wSchemaDefinition.fillTreeItems(); + wSchemaDefinition.fillItems(); } catch (Exception e) { log.logError("Error getting schema definition items", e); } diff --git a/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelwriter/ExcelWriterTransformDialog.java b/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelwriter/ExcelWriterTransformDialog.java index a2dcdb59508..ed23f878530 100644 --- a/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelwriter/ExcelWriterTransformDialog.java +++ b/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelwriter/ExcelWriterTransformDialog.java @@ -1401,7 +1401,7 @@ public void widgetSelected(SelectionEvent e) { wSchemaDefinition.setLayoutData(fdSchemaDefinition); try { - wSchemaDefinition.fillTreeItems(); + wSchemaDefinition.fillItems(); } catch (Exception e) { log.logError("Error getting schema definition items", e); } diff --git a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/csvinput/CsvInputDialog.java b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/csvinput/CsvInputDialog.java index 6d9eadbfee0..8600e7d8fa4 100644 --- a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/csvinput/CsvInputDialog.java +++ b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/csvinput/CsvInputDialog.java @@ -533,7 +533,7 @@ public void focusGained(FocusEvent e) { wSchemaDefinition.setLayoutData(fdSchemaDefinition); try { - wSchemaDefinition.fillTreeItems(); + wSchemaDefinition.fillItems(); } catch (Exception e) { log.logError("Error getting schema definition items", e); } diff --git a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputDialog.java b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputDialog.java index 147ff665fb0..91274487d3b 100644 --- a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputDialog.java +++ b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputDialog.java @@ -1983,7 +1983,7 @@ public void widgetSelected(SelectionEvent e) { wSchemaDefinition.setLayoutData(fdSchemaDefinition); try { - wSchemaDefinition.fillTreeItems(); + wSchemaDefinition.fillItems(); } catch (Exception e) { log.logError("Error getting schema definition items", e); } diff --git a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputDialog.java b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputDialog.java index 2f5bcda1992..89e683122a2 100644 --- a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputDialog.java +++ b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/textfileoutput/TextFileOutputDialog.java @@ -1097,7 +1097,7 @@ public void widgetSelected(SelectionEvent e) { wSchemaDefinition.setLayoutData(fdSchemaDefinition); try { - wSchemaDefinition.fillTreeItems(); + wSchemaDefinition.fillItems(); } catch (Exception e) { log.logError("Error getting schema definition items", e); } diff --git a/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataManager.java b/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataManager.java index b3a43f0ee1c..589026d7dbd 100644 --- a/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataManager.java +++ b/ui/src/main/java/org/apache/hop/ui/core/metadata/MetadataManager.java @@ -447,11 +447,7 @@ public T newMetadata(T element) { } } - public T newMetadataWithEditor() { - return newMetadataWithEditor(""); - } - - public T newMetadataWithEditor(String path) { + public T newMetadataWithEditor(String virtualPath) { HopGui hopGui = HopGui.getInstance(); try { @@ -459,8 +455,8 @@ public T newMetadataWithEditor(String path) { // Create a new instance of the managed class // T element = managedClass.getDeclaredConstructor().newInstance(); - element.setPath(path); initializeElementVariables(element); + element.setVirtualPath(virtualPath); ExtensionPointHandler.callExtensionPoint( hopGui.getLog(), diff --git a/ui/src/main/java/org/apache/hop/ui/core/widget/MetaSelectionLine.java b/ui/src/main/java/org/apache/hop/ui/core/widget/MetaSelectionLine.java index d5725015ec4..d800a903c59 100644 --- a/ui/src/main/java/org/apache/hop/ui/core/widget/MetaSelectionLine.java +++ b/ui/src/main/java/org/apache/hop/ui/core/widget/MetaSelectionLine.java @@ -17,7 +17,6 @@ package org.apache.hop.ui.core.widget; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.lang.StringUtils; @@ -32,7 +31,6 @@ import org.apache.hop.metadata.api.HopMetadata; import org.apache.hop.metadata.api.IHopMetadata; import org.apache.hop.metadata.api.IHopMetadataProvider; -import org.apache.hop.metadata.serializer.FileSystemNode; import org.apache.hop.metadata.util.HopMetadataUtil; import org.apache.hop.ui.core.ConstUi; import org.apache.hop.ui.core.PropsUi; @@ -536,53 +534,4 @@ public ComboVar getwCombo() { public ToolBar getwToolBar() { return wToolBar; } - - /** - * Fills the list of metadata with a flat view of the metadata tree - * - * @throws HopException - */ - public void fillTreeItems() throws HopException { - FileSystemNode rootNode = manager.getSerializer().getFileSystemTree(); - String pathToStrip = getRootFolder(rootNode); - List elementNames = - flattenTree(rootNode).stream() - .map(s -> s.replace(pathToStrip, "")) - .map( - s -> { - if (s.endsWith(".json")) { - return s.replace(".json", ""); - } - return s; - }) - .sorted() - .toList(); - - wCombo.setItems(elementNames.toArray(new String[0])); - } - - private List flattenTree(FileSystemNode rootNode) { - List flatList = new ArrayList<>(); - traverseNode(rootNode, flatList); - return flatList; - } - - private String getRootFolder(FileSystemNode node) { - if (node.getChildren().size() != 1) { - return null; - } - return node.getChildren().get(0).getPath(); - } - - private void traverseNode(FileSystemNode node, List flatList) { - - if (node.isFile()) { - flatList.add(node.getPath()); - } - if (node.isFolder()) { - for (FileSystemNode child : node.getChildren()) { - traverseNode(child, flatList); - } - } - } } diff --git a/ui/src/main/java/org/apache/hop/ui/core/widget/TableView.java b/ui/src/main/java/org/apache/hop/ui/core/widget/TableView.java index 08c9a33248e..ace9505c331 100644 --- a/ui/src/main/java/org/apache/hop/ui/core/widget/TableView.java +++ b/ui/src/main/java/org/apache/hop/ui/core/widget/TableView.java @@ -2665,8 +2665,10 @@ private void setColumnWidthBasedOnTextField(final int colNr, final boolean useVa int strmax = TextSizeUtilFacade.textExtent(str).x + 20; int colmax = tableColumn[colNr].getWidth(); if (strmax > colmax) { - if (!EnvironmentUtils.getInstance().isWeb() && (Const.isOSX() || Const.isLinux())) { - strmax *= 1.4; + if (!EnvironmentUtils.getInstance().isWeb()) { + if (Const.isOSX() || Const.isLinux()) { + strmax *= 1.4; + } } tableColumn[colNr].setWidth(strmax + 30); @@ -3045,14 +3047,14 @@ private boolean isEmpty(int rowNr, int colNr) { if (item != null) { if (colNr >= 0) { String str = item.getText(colNr); - if (str == null || str.isEmpty()) { + if (str == null || str.length() == 0) { empty = true; } } else { empty = true; for (int j = 1; j < table.getColumnCount(); j++) { String str = item.getText(j); - if (str != null && !str.isEmpty()) { + if (str != null && str.length() > 0) { empty = false; } } diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/context/metadata/MetadataContextHandler.java b/ui/src/main/java/org/apache/hop/ui/hopgui/context/metadata/MetadataContextHandler.java index 521751503e0..d1342a4dfa2 100644 --- a/ui/src/main/java/org/apache/hop/ui/hopgui/context/metadata/MetadataContextHandler.java +++ b/ui/src/main/java/org/apache/hop/ui/hopgui/context/metadata/MetadataContextHandler.java @@ -81,7 +81,8 @@ public List getSupportedActions() { + " : " + TranslateUtil.translate(hopMetadata.description(), metadataObjectClass), hopMetadata.image(), - (shiftClicked, controlClicked, parameters) -> metadataManager.newMetadataWithEditor()); + (shiftClicked, controlClicked, parameters) -> + metadataManager.newMetadataWithEditor("")); newAction.setClassLoader(metadataObjectClass.getClassLoader()); newAction.setCategory(CONST_METADATA); newAction.setCategoryOrder("2"); diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java index c1682c391b1..a13b5644d3e 100644 --- a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java +++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java @@ -17,39 +17,35 @@ package org.apache.hop.ui.hopgui.perspective.metadata; -import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import org.apache.commons.vfs2.FileObject; +import org.apache.commons.lang.StringUtils; import org.apache.hop.core.Const; import org.apache.hop.core.Props; import org.apache.hop.core.exception.HopException; import org.apache.hop.core.gui.plugin.GuiPlugin; import org.apache.hop.core.gui.plugin.key.GuiKeyboardShortcut; import org.apache.hop.core.gui.plugin.key.GuiOsxKeyboardShortcut; -import org.apache.hop.core.gui.plugin.menu.GuiMenuElement; import org.apache.hop.core.gui.plugin.toolbar.GuiToolbarElement; 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.util.TranslateUtil; -import org.apache.hop.core.vfs.HopVfs; import org.apache.hop.i18n.BaseMessages; import org.apache.hop.metadata.api.HopMetadata; import org.apache.hop.metadata.api.IHopMetadata; import org.apache.hop.metadata.api.IHopMetadataProvider; import org.apache.hop.metadata.api.IHopMetadataSerializer; import org.apache.hop.metadata.plugin.MetadataPluginType; -import org.apache.hop.metadata.serializer.FileSystemNode; import org.apache.hop.metadata.util.HopMetadataUtil; import org.apache.hop.ui.core.ConstUi; import org.apache.hop.ui.core.PropsUi; import org.apache.hop.ui.core.bus.HopGuiEvents; import org.apache.hop.ui.core.dialog.EnterStringDialog; import org.apache.hop.ui.core.dialog.ErrorDialog; -import org.apache.hop.ui.core.gui.GuiMenuWidgets; +import org.apache.hop.ui.core.dialog.ShowMessageDialog; import org.apache.hop.ui.core.gui.GuiResource; import org.apache.hop.ui.core.gui.GuiToolbarWidgets; import org.apache.hop.ui.core.metadata.MetadataEditor; @@ -87,6 +83,7 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.ToolBar; @@ -105,33 +102,15 @@ public class MetadataPerspective implements IHopPerspective, TabClosable { public static final Class PKG = MetadataPerspective.class; // i18n private static final String METADATA_PERSPECTIVE_TREE = "Metadata perspective tree"; - public static final String GUI_PLUGIN_CONTEXT_MENU_PARENT_ID = "MetadataPerspective-Toolbar"; public static final String GUI_PLUGIN_TOOLBAR_PARENT_ID = "MetadataPerspective-Toolbar"; public static final String TOOLBAR_ITEM_NEW = "MetadataPerspective-Toolbar-10000-New"; - public static final String TOOLBAR_ITEM_CREATE_FOLDER = - "MetadataPerspective-Toolbar-10010-Create-Folder"; - public static final String TOOLBAR_ITEM_EDIT = "MetadataPerspective-Toolbar-10020-Edit"; - public static final String TOOLBAR_ITEM_RENAME = "MetadataPerspective-Toolbar-10030-Rename"; - public static final String TOOLBAR_ITEM_DUPLICATE = "MetadataPerspective-Toolbar-10040-Duplicate"; - public static final String TOOLBAR_ITEM_DELETE = "MetadataPerspective-Toolbar-10050-Delete"; + public static final String TOOLBAR_ITEM_EDIT = "MetadataPerspective-Toolbar-10010-Edit"; + public static final String TOOLBAR_ITEM_DUPLICATE = "MetadataPerspective-Toolbar-10030-Duplicate"; + public static final String TOOLBAR_ITEM_DELETE = "MetadataPerspective-Toolbar-10040-Delete"; public static final String TOOLBAR_ITEM_REFRESH = "MetadataPerspective-Toolbar-10100-Refresh"; public static final String KEY_HELP = "Help"; - private static final String SUBFOLDERS_ENABLED = "SubFoldersEnabled"; - - private static final String CONTEXT_MENU_NEW = "MetadataPerspective-ContextMenu-10000-New"; - private static final String CONTEXT_MENU_CREATE_FOLDER = - "MetadataPerspective-ContextMenu-10010-Create-Folder"; - private static final String CONTEXT_MENU_EDIT = "MetadataPerspective-ContextMenu-10020-Edit"; - public static final String CONTEXT_MENU_RENAME = "MetadataPerspective-ContextMenu-10030-Rename"; - private static final String CONTEXT_MENU_DUPLICATE = - "MetadataPerspective-ContextMenu-10040-Duplicate"; - private static final String CONTEXT_MENU_DELETE = "MetadataPerspective-ContextMenu-10050-Delete"; - private static final String CONTEXT_MENU_HELP = "MetadataPerspective-ContextMenu-10050-Help"; - public static final String PATH = "path"; - public static final String CONST_FOLDER = "FOLDER"; - public static final String CONST_ERROR = "Error"; private static MetadataPerspective instance; @@ -146,7 +125,6 @@ public static MetadataPerspective getInstance() { private CTabFolder tabFolder; private ToolBar toolBar; private GuiToolbarWidgets toolBarWidgets; - private GuiMenuWidgets menuWidgets; private List> editors = new ArrayList<>(); @@ -277,13 +255,63 @@ protected void createTree(Composite parent) { } } }); - PropsUi.setLook(tree); - Menu menu = new Menu(tree); - menuWidgets = new GuiMenuWidgets(); - menuWidgets.registerGuiPluginObject(this); - menuWidgets.createMenuWidgets(GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, getShell(), menu); - tree.setMenu(menu); + tree.addMenuDetectListener( + event -> { + if (tree.getSelectionCount() < 1) { + return; + } + + TreeItem treeItem = tree.getSelection()[0]; + if (treeItem != null) { + // Show the menu + // + Menu menu = new Menu(tree); + MenuItem menuItem; + + switch ((String) treeItem.getData("type")) { + case "MetadataItem": + case "Folder": + menuItem = new MenuItem(menu, SWT.POP_UP); + menuItem.setText(BaseMessages.getString(PKG, "MetadataPerspective.Menu.New")); + menuItem.addListener(SWT.Selection, e -> onNewMetadata()); + menuItem = new MenuItem(menu, SWT.POP_UP); + menuItem.setText(BaseMessages.getString(PKG, "MetadataPerspective.Menu.NewFolder")); + menuItem.addListener(SWT.Selection, e -> createNewFolder()); + new MenuItem(menu, SWT.SEPARATOR); + break; + case "File": + menuItem = new MenuItem(menu, SWT.POP_UP); + menuItem.setText(BaseMessages.getString(PKG, "MetadataPerspective.Menu.Edit")); + menuItem.addListener(SWT.Selection, e -> onEditMetadata()); + + menuItem = new MenuItem(menu, SWT.POP_UP); + menuItem.setText(BaseMessages.getString(PKG, "MetadataPerspective.Menu.Rename")); + menuItem.addListener(SWT.Selection, e -> onRenameMetadata()); + + menuItem = new MenuItem(menu, SWT.POP_UP); + menuItem.setText(BaseMessages.getString(PKG, "MetadataPerspective.Menu.Duplicate")); + menuItem.addListener(SWT.Selection, e -> duplicateMetadata()); + + new MenuItem(menu, SWT.SEPARATOR); + + menuItem = new MenuItem(menu, SWT.POP_UP); + menuItem.setText(BaseMessages.getString(PKG, "MetadataPerspective.Menu.Delete")); + menuItem.addListener(SWT.Selection, e -> onDeleteMetadata()); + + new MenuItem(menu, SWT.SEPARATOR); + break; + } + + menuItem = new MenuItem(menu, SWT.POP_UP); + menuItem.setText(BaseMessages.getString(PKG, "MetadataPerspective.Menu.Help")); + menuItem.addListener(SWT.Selection, e -> onHelpMetadata()); + + tree.setMenu(menu); + menu.setVisible(true); + } + }); + PropsUi.setLook(tree); FormData treeFormData = new FormData(); treeFormData.left = new FormAttachment(0, 0); @@ -477,20 +505,11 @@ protected void onTabClose(CTabFolderEvent event) { closeTab(event, tabItem); } - @GuiMenuElement( - root = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - parentId = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - id = CONTEXT_MENU_NEW, - label = "i18n::MetadataPerspective.Menu.New.Label", - toolTip = "i18n::MetadataPerspective.Menu.New.Tooltip", - image = "ui/images/new.svg") @GuiToolbarElement( root = GUI_PLUGIN_TOOLBAR_PARENT_ID, id = TOOLBAR_ITEM_NEW, toolTip = "i18n::MetadataPerspective.ToolbarElement.New.Tooltip", image = "ui/images/new.svg") - @GuiKeyboardShortcut(key = SWT.F2) - @GuiOsxKeyboardShortcut(key = SWT.F2) public void onNewMetadata() { if (tree.getSelectionCount() != 1) { return; @@ -502,7 +521,7 @@ public void onNewMetadata() { if (treeItem.getParentItem() == null) { objectKey = (String) treeItem.getData(); } else { - objectKey = getMetadataClassKey(treeItem.getParentItem()); + objectKey = (String) treeItem.getParentItem().getData(); } try { @@ -515,7 +534,7 @@ public void onNewMetadata() { metadataClass, hopGui.getShell()); - manager.newMetadataWithEditor(getMetadataObjectPath(treeItem)); + manager.newMetadataWithEditor((String) treeItem.getData("virtualPath")); hopGui.getEventsHandler().fire(HopGuiEvents.MetadataCreated.name()); } catch (Exception e) { @@ -528,83 +547,6 @@ public void onNewMetadata() { } } - @GuiMenuElement( - root = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - parentId = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - id = CONTEXT_MENU_CREATE_FOLDER, - label = "i18n::MetadataPerspective.Menu.NewFolder.Label", - toolTip = "i18n::MetadataPerspective.Menu.NewFolder.Tooltip", - image = "ui/images/folder-add.svg") - @GuiToolbarElement( - root = GUI_PLUGIN_TOOLBAR_PARENT_ID, - id = TOOLBAR_ITEM_CREATE_FOLDER, - toolTip = "i18n::MetadataPerspective.ToolbarElement.NewFolder.Tooltip", - image = "ui/images/folder-add.svg") - @GuiKeyboardShortcut(key = SWT.F3) - @GuiOsxKeyboardShortcut(key = SWT.F3) - public void onNewFolder() { - String rootFolder = hopGui.getVariables().getVariable("HOP_METADATA_FOLDER"); - if (!rootFolder.endsWith(File.separator) && !rootFolder.endsWith("\\")) { - rootFolder += File.separator; - } - TreeItem[] selection = tree.getSelection(); - if (selection == null || selection.length == 0) { - return; - } - TreeItem item = selection[0]; - if (Boolean.FALSE.equals(Boolean.valueOf(item.getData(SUBFOLDERS_ENABLED).toString()))) { - new ErrorDialog( - getShell(), - CONST_ERROR, - "Could not create subfolder for this metadata category", - new HopException("Could not create subfolder for this metadata category")); - return; - } - String tif = getMetadataObjectPath(item, false); - if (tif == null) { - return; - } - EnterStringDialog dialog = - new EnterStringDialog( - getShell(), - "", - BaseMessages.getString(PKG, "MetadataPerspective.CreateFolder.Header"), - BaseMessages.getString(PKG, "MetadataPerspective.CreateFolder.Message", tif)); - String folder = dialog.open(); - if (folder != null) { - String newPath = tif; - if (!newPath.endsWith("/") && !newPath.endsWith("\\")) { - newPath += "/"; - } - newPath += folder; - try { - FileObject newFolder = HopVfs.getFileObject(newPath); - newFolder.createFolder(); - - refresh(); - } catch (Throwable e) { - new ErrorDialog( - getShell(), - BaseMessages.getString(PKG, "ExplorerPerspective.Error.CreateFolder.Header"), - BaseMessages.getString(PKG, "ExplorerPerspective.Error.CreateFolder.Message", newPath), - e); - } - } - } - - @GuiMenuElement( - root = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - parentId = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - id = CONTEXT_MENU_EDIT, - label = "i18n::MetadataPerspective.Menu.Edit.Label", - toolTip = "i18n::MetadataPerspective.Menu.Edit.Tooltip", - image = "ui/images/edit.svg", - separator = true) - @GuiToolbarElement( - root = GUI_PLUGIN_TOOLBAR_PARENT_ID, - id = TOOLBAR_ITEM_EDIT, - toolTip = "i18n::MetadataPerspective.ToolbarElement.Edit.Tooltip", - image = "ui/images/edit.svg") public void onEditMetadata() { if (tree.getSelectionCount() != 1) { return; @@ -612,8 +554,8 @@ public void onEditMetadata() { TreeItem treeItem = tree.getSelection()[0]; if (treeItem != null && treeItem.getParentItem() != null) { - String objectKey = getMetadataClassKey(treeItem.getParentItem()); - String objectName = getMetadataObjectName(treeItem); + String objectKey = (String) treeItem.getParentItem().getData(); + String objectName = treeItem.getText(0); MetadataEditor editor = this.findEditor(objectKey, objectName); if (editor != null) { @@ -625,7 +567,7 @@ public void onEditMetadata() { hopGui.getEventsHandler().fire(HopGuiEvents.MetadataChanged.name()); } catch (Exception e) { - new ErrorDialog(getShell(), CONST_ERROR, "Error editing metadata", e); + new ErrorDialog(getShell(), "Error", "Error editing metadata", e); } } @@ -633,25 +575,11 @@ public void onEditMetadata() { } } - private static String getMetadataClassKey(TreeItem treeItem) { - while (treeItem.getParentItem() != null) { - return getMetadataClassKey(treeItem.getParentItem()); - } - return (String) treeItem.getData(); - } - - @GuiMenuElement( - root = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - parentId = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - id = CONTEXT_MENU_RENAME, - label = "i18n::MetadataPerspective.Menu.Rename.Label", - toolTip = "i18n::MetadataPerspective.Menu.Rename.Tooltip", - image = "ui/images/rename.svg") @GuiToolbarElement( root = GUI_PLUGIN_TOOLBAR_PARENT_ID, - id = TOOLBAR_ITEM_RENAME, + id = TOOLBAR_ITEM_EDIT, toolTip = "i18n::MetadataPerspective.ToolbarElement.Edit.Tooltip", - image = "ui/images/rename.svg") + image = "ui/images/edit.svg") public void onRenameMetadata() { if (tree.getSelectionCount() < 1) { @@ -709,71 +637,36 @@ public void onRenameMetadata() { } } - private String getMetadataObjectName(TreeItem treeItem) { - return getMetadataObjectName(treeItem, false); - } + @GuiToolbarElement( + root = GUI_PLUGIN_TOOLBAR_PARENT_ID, + id = TOOLBAR_ITEM_DELETE, + toolTip = "i18n::MetadataPerspective.ToolbarElement.Delete.Tooltip", + image = "ui/images/delete.svg") + public void onDeleteMetadata() { - private String getMetadataObjectName(TreeItem treeItem, Boolean showMetadataClassFolder) { - if (treeItem.getData(PATH).toString().endsWith(".json")) { - return treeItem.getData(PATH).toString(); + if (tree.getSelectionCount() != 1) { + return; } - String path = treeItem.getData(PATH).toString(); - TreeItem parent = treeItem.getParentItem(); - if (Boolean.TRUE.equals(showMetadataClassFolder)) { - while (parent != null) { - if (parent.getParentItem() == null) { - path = parent.getData() + File.separator + path; - } else { - path = parent.getText(0) + File.separator + path; - } - parent = parent.getParentItem(); - } - } else { - while (parent != null && parent.getParentItem() != null) { - path = parent.getText(0) + File.separator + path; - parent = parent.getParentItem(); - } - } - return path; - } + TreeItem treeItem = tree.getSelection()[0]; + if (treeItem != null && treeItem.getParentItem() != null) { + String objectKey = (String) treeItem.getParentItem().getData(); + String objectName = treeItem.getText(0); - private String getMetadataObjectPath(TreeItem treeItem) { - return getMetadataObjectPath(treeItem, false); - } + try { + MetadataManager manager = getMetadataManager(objectKey); + manager.deleteMetadata(objectName); - // THIS should return only a relative path - private String getMetadataObjectPath(TreeItem treeItem, Boolean showMetadataClassFolder) { - String path = treeItem.getData(PATH).toString(); - TreeItem parent = treeItem.getParentItem(); - if (Boolean.TRUE.equals(showMetadataClassFolder)) { - while (parent != null) { - if (parent.getParentItem() == null) { - path = parent.getData() + File.separator + path; - } else { - path = parent.getText(0) + File.separator + path; - } + refresh(); + updateSelection(); - parent = parent.getParentItem(); - } - } else { - while (parent != null && parent.getParentItem() != null) { - if (!path.startsWith(parent.getData(PATH).toString())) { - path = parent.getData(PATH) + File.separator + path; - } - parent = parent.getParentItem(); + hopGui.getEventsHandler().fire(HopGuiEvents.MetadataDeleted.name()); + } catch (Exception e) { + new ErrorDialog(getShell(), "Error", "Error delete metadata", e); } } - - return path; } - @GuiMenuElement( - root = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - parentId = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - id = CONTEXT_MENU_DUPLICATE, - label = "i18n::MetadataPerspective.Menu.Duplicate.Label", - image = "ui/images/duplicate.svg") @GuiToolbarElement( root = GUI_PLUGIN_TOOLBAR_PARENT_ID, id = TOOLBAR_ITEM_DUPLICATE, @@ -787,8 +680,8 @@ public void duplicateMetadata() { TreeItem treeItem = tree.getSelection()[0]; if (treeItem != null && treeItem.getParentItem() != null) { - String objectKey = getMetadataClassKey(treeItem.getParentItem()); - String objectName = getMetadataObjectName(treeItem); + String objectKey = (String) treeItem.getParentItem().getData(); + String objectName = treeItem.getText(0); try { MetadataManager manager = getMetadataManager(objectKey); @@ -818,53 +711,6 @@ public void duplicateMetadata() { } } - @GuiMenuElement( - root = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - parentId = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - id = CONTEXT_MENU_DELETE, - label = "i18n::MetadataPerspective.Menu.Delete.Label", - toolTip = "i18n::MetadataPerspective.Menu.Delete.Tooltip", - image = "ui/images/delete.svg") - @GuiToolbarElement( - root = GUI_PLUGIN_TOOLBAR_PARENT_ID, - id = TOOLBAR_ITEM_DELETE, - toolTip = "i18n::MetadataPerspective.ToolbarElement.Delete.Tooltip", - image = "ui/images/delete.svg") - @GuiKeyboardShortcut(key = SWT.DEL) - @GuiOsxKeyboardShortcut(key = SWT.DEL) - public void onDeleteMetadata() { - - if (tree.getSelectionCount() != 1) { - return; - } - - TreeItem treeItem = tree.getSelection()[0]; - if (treeItem != null && treeItem.getData("type") != null) { - String objectKey = getMetadataClassKey(treeItem.getParentItem()); - String objectName = getMetadataObjectName(treeItem); - - try { - MetadataManager manager = getMetadataManager(objectKey); - manager.deleteMetadata(objectName); - - refresh(); - updateSelection(); - - hopGui.getEventsHandler().fire(HopGuiEvents.MetadataDeleted.name()); - } catch (Exception e) { - new ErrorDialog(getShell(), CONST_ERROR, "Error delete metadata", e); - } - } - } - - @GuiMenuElement( - root = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - parentId = GUI_PLUGIN_CONTEXT_MENU_PARENT_ID, - id = CONTEXT_MENU_HELP, - label = "i18n::MetadataPerspective.Menu.Help.Label", - toolTip = "i18n::MetadataPerspective.Menu.Help.Tooltip", - image = "ui/images/help.svg", - separator = true) public void onHelpMetadata() { if (tree.getSelectionCount() != 1) { @@ -887,7 +733,7 @@ public void onHelpMetadata() { PluginRegistry.getInstance().getPlugin(MetadataPluginType.class, annotation.key()); HelpUtils.openHelp(getShell(), plugin); } catch (Exception ex) { - new ErrorDialog(getShell(), CONST_ERROR, "Error opening URL", ex); + new ErrorDialog(getShell(), "Error", "Error opening URL", ex); } } } @@ -946,8 +792,7 @@ public void refresh() { HopMetadata a2 = HopMetadataUtil.getHopMetadataAnnotation(cl2); return a1.name().compareTo(a2.name()); }); - // Iterate over metadataClass, meaning all the elements at the top level in the metadata tree - // (Schema Definitions, Database, Neo4j, Mongo.... + for (Class metadataClass : metadataClasses) { HopMetadata annotation = HopMetadataUtil.getHopMetadataAnnotation(metadataClass); Image image = @@ -965,17 +810,64 @@ public void refresh() { classItem.setExpanded(true); classItem.setData(annotation.key()); classItem.setData(KEY_HELP, annotation.description()); - classItem.setData("type", CONST_FOLDER); - classItem.setData(SUBFOLDERS_ENABLED, Boolean.valueOf(annotation.subfoldersEnabled())); + classItem.setData("virtualPath", ""); + classItem.setData("type", "MetadataItem"); - // level 1: object names: folders and definitions + // level 1: object names // IHopMetadataSerializer serializer = metadataProvider.getSerializer(metadataClass); - final FileSystemNode metadataItemRoot = serializer.getFileSystemTree(); - classItem.setData(PATH, metadataItemRoot.getChildren().get(0).getPath()); + List names = serializer.listObjectNames(); + Collections.sort(names); + + for (final String name : names) { + IHopMetadata hopMetadata = serializer.load(name); + TreeItem parentItem = classItem; + + if (hopMetadata.getVirtualPath() != null && !hopMetadata.getVirtualPath().isEmpty()) { + List folders = + new ArrayList<>(Arrays.asList(hopMetadata.getVirtualPath().split("/"))); + // remove empty elements + folders.removeAll(Arrays.asList("", null)); + + for (String folder : folders) { + TreeItem alreadyExists = null; + if (!folder.isEmpty()) { + // check if folder already exists on this level + alreadyExists = null; + for (TreeItem childItem : parentItem.getItems()) { + if (childItem.getData("type").equals("Folder") + && childItem.getText().equals(folder)) { + alreadyExists = childItem; + } + } + + if (alreadyExists != null) { + parentItem = alreadyExists; + } else { + TreeItem folderItem = new TreeItem(parentItem, SWT.NONE); + folderItem.setText(folder); + folderItem.setData(annotation.key()); + folderItem.setImage(GuiResource.getInstance().getImageFolder()); + folderItem.setData( + "virtualPath", + folderItem.getParentItem().getData("virtualPath") + "/" + folder); + folderItem.setData("type", "Folder"); + parentItem = folderItem; + } + } + } + } - appendChildren(classItem, metadataItemRoot.getChildren().get(0), annotation); + TreeItem item = new TreeItem(parentItem, SWT.NONE); + item.setText(0, Const.NVL(name, "")); + item.setData("virtualPath", parentItem.getData("virtualPath")); + item.setData("type", "File"); + MetadataEditor editor = this.findEditor(annotation.key(), name); + if (editor != null && editor.hasChanged()) { + item.setFont(GuiResource.getInstance().getFontBold()); + } + } } TreeUtil.setOptimalWidthOnColumns(tree); @@ -993,110 +885,44 @@ public void refresh() { } } - private void appendChildren( - TreeItem parentItem, FileSystemNode rootNode, HopMetadata annotation) { - for (final FileSystemNode node : rootNode.getChildren()) { - TreeItem item = new TreeItem(parentItem, SWT.NONE); - item.setText(0, Const.NVL(node.getName(), "")); - item.setData(node.getName()); - item.setData(PATH, node.getPath()); - item.setData(SUBFOLDERS_ENABLED, item.getParentItem().getData(SUBFOLDERS_ENABLED)); - switch (node.getType()) { - case FILE: - item.setData("type", "FILE"); - break; - case FOLDER: - item.setImage(GuiResource.getInstance().getImage("ui/images/folder.svg")); - item.setData("type", CONST_FOLDER); - appendChildren(item, node, annotation); - break; - default: - break; - } - MetadataEditor editor = this.findEditor(annotation.key(), node.getName()); - if (editor != null && editor.hasChanged()) { - item.setFont(GuiResource.getInstance().getFontBold()); - } - } - } - - private enum TreeItemType { - FILE, - FOLDER; - - public static boolean isFile(TreeItemType type) { - return FILE == type; - } - - public static boolean isFolder(TreeItemType type) { - return FOLDER == type; - } - - public static boolean isFile(Object type) { - String typeStr; - try { - typeStr = (String) type; - } catch (ClassCastException e) { - return false; - } - TreeItemType value = TreeItemType.valueOf(typeStr); - return isFile(value); - } - } - protected void updateSelection() { String objectName = null; - TreeItemType type = null; - Boolean subFolderEnabled = false; - if (tree.getSelectionCount() > 0) { TreeItem selectedItem = tree.getSelection()[0]; - if (selectedItem.getData("type") == null - || selectedItem.getData("type").equals(CONST_FOLDER)) { + if (selectedItem.getParentItem() == null) { objectName = null; - type = TreeItemType.FOLDER; } else { - objectName = getMetadataObjectName(selectedItem); - type = TreeItemType.FILE; + objectName = selectedItem.getText(0); } - - subFolderEnabled = Boolean.valueOf(selectedItem.getData(SUBFOLDERS_ENABLED).toString()); } - boolean isFile = TreeItemType.isFile(type); - boolean isFolder = TreeItemType.isFolder(type); - - toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_NEW, isFile); - toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_CREATE_FOLDER, isFolder && subFolderEnabled); - toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_EDIT, isFile); - toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_DUPLICATE, isFile); - toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_DELETE, isFile); - - menuWidgets.enableMenuItem(CONTEXT_MENU_NEW, isFolder); - menuWidgets.enableMenuItem(CONTEXT_MENU_CREATE_FOLDER, isFolder && subFolderEnabled); - menuWidgets.enableMenuItem(CONTEXT_MENU_EDIT, isFile); - menuWidgets.enableMenuItem(CONTEXT_MENU_DUPLICATE, isFile); + toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_EDIT, StringUtils.isNotEmpty(objectName)); + toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_DUPLICATE, StringUtils.isNotEmpty(objectName)); + toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_DELETE, StringUtils.isNotEmpty(objectName)); } @Override public boolean remove(IHopFileTypeHandler typeHandler) { - if (typeHandler instanceof MetadataEditor editor && editor.isCloseable()) { - editors.remove(editor); + if (typeHandler instanceof MetadataEditor editor) { + if (editor.isCloseable()) { + + editors.remove(editor); - for (CTabItem item : tabFolder.getItems()) { - if (editor.equals(item.getData())) { - item.dispose(); + for (CTabItem item : tabFolder.getItems()) { + if (editor.equals(item.getData())) { + item.dispose(); + } } - } - // Refresh tree to remove bold - // - this.refresh(); + // Refresh tree to remove bold + // + this.refresh(); - // Update Gui menu and toolbar - this.updateGui(); + // Update Gui menu and toolbar + this.updateGui(); + } } return false; @@ -1225,30 +1051,42 @@ public void goToElement(Class managedClass, String eleme } } - private class TreeItemFolder { - public TreeItem treeItem; - public String path; - public String name; - public IHopFileType fileType; - public int depth; - public boolean folder; - public boolean loaded; - - public TreeItemFolder( - TreeItem treeItem, - String path, - String name, - IHopFileType fileType, - int depth, - boolean folder, - boolean loaded) { - this.treeItem = treeItem; - this.path = path; - this.name = name; - this.fileType = fileType; - this.depth = depth; - this.folder = folder; - this.loaded = loaded; + public void createNewFolder() { + TreeItem[] selection = tree.getSelection(); + if (selection == null || selection.length == 0) { + return; + } + TreeItem item = selection[0]; + EnterStringDialog dialog = + new EnterStringDialog( + getShell(), + "", + BaseMessages.getString(PKG, "MetadataPerspective.CreateFolder.Header"), + BaseMessages.getString( + PKG, + "MetadataPerspective.CreateFolder.Message", + (String) item.getData("virtualPath"))); + String folder = dialog.open(); + if (folder != null) { + for (TreeItem treeItem : item.getItems()) { + if (folder.equals(treeItem.getText())) { + ShowMessageDialog msgDialog = + new ShowMessageDialog( + getShell(), + SWT.ICON_INFORMATION | SWT.OK, + BaseMessages.getString(PKG, "MetadataPerspective.CreateFolder.Error.Header"), + BaseMessages.getString(PKG, "MetadataPerspective.CreateFolder.Error.Message"), + false); + msgDialog.open(); + return; + } + } + TreeItem newFolder = new TreeItem(item, SWT.NONE); + newFolder.setText(folder); + newFolder.setData(item.getData()); + newFolder.setImage(GuiResource.getInstance().getImageFolder()); + newFolder.setData("virtualPath", item.getData("virtualPath") + "/" + folder); + newFolder.setData("type", "Folder"); } } } diff --git a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties index ba65410b068..d60c7e23651 100644 --- a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties +++ b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties @@ -15,7 +15,6 @@ # limitations under the License. # -MetadataPerspective.CreateFolder.Message=Enter name of the folder to create MetadataPerspective.CreateMetadata.Error.Header=Error MetadataPerspective.CreateMetadata.Error.Message=Error creating metadata MetadataPerspective.Description=The Hop Metatada Perspective @@ -24,28 +23,22 @@ MetadataPerspective.DuplicateMetadata.Error.Message=Error duplicating metadata MetadataPerspective.EditMetadata.Error.Header=Error MetadataPerspective.EditMetadata.Error.Message=Error editing metadata MetadataPerspective.GuiPlugin.Description=This perspective allows you to see and edit all available metadata -MetadataPerspective.Menu.Edit.Label=Edit -MetadataPerspective.Menu.Edit.Tooltip=Edit selected metadata element -MetadataPerspective.Menu.New.Label=New -MetadataPerspective.Menu.New.Tooltip=Create a new metadata element -MetadataPerspective.Menu.NewFolder.Label=Create folder -MetadataPerspective.Menu.NewFolder.Tooltip=Create a new metadata folder -MetadataPerspective.Menu.Refresh.Label=Refresh -MetadataPerspective.Menu.Refresh.Tooltip=Refresh metadata tree -MetadataPerspective.Menu.Rename.Label=Rename -MetadataPerspective.Menu.Rename.Tooltip=Rename selected metadata element -MetadataPerspective.Menu.Delete.Label=Delete -MetadataPerspective.Menu.Delete.Tooltip=Delete selected metadata element -MetadataPerspective.Menu.Duplicate.Label=Duplicate -MetadataPerspective.Menu.Duplicate.Tooltip=Duplicate selected metadata element -MetadataPerspective.Menu.Help.Label=Help -MetadataPerspective.Menu.Help.Tooltip=Help on the metadata perspective - MetadataPerspective.Name=Metadata MetadataPerspective.RefreshMetadata.Error.Header=Error MetadataPerspective.RefreshMetadata.Error.Message=Error refreshing metadata tree MetadataPerspective.ToolbarElement.CreateCopy.Tooltip=Create a copy MetadataPerspective.ToolbarElement.Delete.Tooltip=Delete -MetadataPerspective.ToolbarElement.Edit.Tooltip=Edit selected metadata element +MetadataPerspective.ToolbarElement.Edit.Tooltip=Edit MetadataPerspective.ToolbarElement.New.Tooltip=Create a new metadata element MetadataPerspective.ToolbarElement.Refresh.Tooltip=Refresh +MetadataPerspective.CreateFolder.Header=Create directory +MetadataPerspective.CreateFolder.Message=Please enter name of the folder to create in: ''{0}'' +MetadataPerspective.CreateFolder.Error.Header=Cannot Create folder +MetadataPerspective.CreateFolder.Error.Message=Folder already exists +MetadataPerspective.Menu.New=New +MetadataPerspective.Menu.NewFolder=New Folder +MetadataPerspective.Menu.Edit=Edit +MetadataPerspective.Menu.Rename=Rename +MetadataPerspective.Menu.Duplicate=Duplicate +MetadataPerspective.Menu.Delete=Delete +MetadataPerspective.Menu.Help=Help \ No newline at end of file