This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new b034338849 Fix file paths in "Export current project to zip" #5662. 
(#5771)
b034338849 is described below

commit b034338849498207d4932e121e22bb216fa8c11e
Author: Nicolas Adment <[email protected]>
AuthorDate: Mon Oct 6 09:33:53 2025 +0200

    Fix file paths in "Export current project to zip" #5662. (#5771)
    
    Refactor dialog layout management.
    Prevent the zip file from including itself.
---
 .../apache/hop/projects/gui/ProjectsGuiPlugin.java | 195 ++++++++++-----------
 .../gui/messages/messages_en_US.properties         |   2 +-
 .../org/apache/hop/ui/core/widget/FileTree.java    |  42 ++---
 3 files changed, 111 insertions(+), 128 deletions(-)

diff --git 
a/plugins/misc/projects/src/main/java/org/apache/hop/projects/gui/ProjectsGuiPlugin.java
 
b/plugins/misc/projects/src/main/java/org/apache/hop/projects/gui/ProjectsGuiPlugin.java
index 2a867425de..ece133c9c9 100644
--- 
a/plugins/misc/projects/src/main/java/org/apache/hop/projects/gui/ProjectsGuiPlugin.java
+++ 
b/plugins/misc/projects/src/main/java/org/apache/hop/projects/gui/ProjectsGuiPlugin.java
@@ -69,6 +69,7 @@ import org.apache.hop.projects.project.Project;
 import org.apache.hop.projects.project.ProjectConfig;
 import org.apache.hop.projects.project.ProjectDialog;
 import org.apache.hop.projects.util.ProjectsUtil;
+import org.apache.hop.ui.core.FormDataBuilder;
 import org.apache.hop.ui.core.PropsUi;
 import org.apache.hop.ui.core.bus.HopGuiEvents;
 import org.apache.hop.ui.core.dialog.BaseDialog;
@@ -82,11 +83,11 @@ import org.apache.hop.ui.core.vfs.HopVfsFileDialog;
 import org.apache.hop.ui.core.widget.FileTree;
 import org.apache.hop.ui.hopgui.HopGui;
 import org.apache.hop.ui.pipeline.dialog.PipelineExecutionConfigurationDialog;
+import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
 import org.apache.hop.workflow.config.WorkflowRunConfiguration;
 import org.apache.hop.workflow.engines.local.LocalWorkflowRunConfiguration;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.FormLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Combo;
 import org.eclipse.swt.widgets.Control;
@@ -467,7 +468,7 @@ public class ProjectsGuiPlugin {
     if (config.isEnvironmentsForActiveProject() && 
StringUtils.isEmpty(projectName)) {
       // list all environments and select the first one if we don't have a 
project selected
       List<String> allEnvironments = config.listEnvironmentNames();
-      environmentsCombo.setItems(allEnvironments.toArray(new 
String[allEnvironments.size()]));
+      environmentsCombo.setItems(allEnvironments.toArray(new String[0]));
       selectEnvironmentInList(allEnvironments.get(0));
       return;
     }
@@ -478,13 +479,11 @@ public class ProjectsGuiPlugin {
       // get the environments for the selected project.
       if (environmentsCombo != null) {
         List<String> projectEnvironments = 
config.listEnvironmentNamesForProject(projectName);
-        environmentsCombo.setItems(
-            projectEnvironments.toArray(new 
String[projectEnvironments.size()]));
+        environmentsCombo.setItems(projectEnvironments.toArray(new String[0]));
       }
     } else {
       List<String> projectEnvironments = config.listEnvironmentNames();
-      environmentsCombo.setItems(
-          projectEnvironments.toArray(new String[projectEnvironments.size()]));
+      environmentsCombo.setItems(projectEnvironments.toArray(new String[0]));
     }
 
     // What is the last used environment?
@@ -1123,55 +1122,17 @@ public class ProjectsGuiPlugin {
       Shell treeShell =
           new Shell(
               shell, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MIN | SWT.MAX | 
SWT.APPLICATION_MODAL);
-      PropsUi.setLook(treeShell);
+      treeShell.setText(BaseMessages.getString(PKG, 
"HopGui.FileMenu.Project.Export.Label"));
       treeShell.setImage(GuiResource.getInstance().getImageHopUi());
+      treeShell.setMinimumSize(500, 300);
       PropsUi.setLook(treeShell);
-      treeShell.setMinimumSize(500, 200);
-
-      GridLayout layout = new GridLayout();
-      layout.numColumns = 4;
-      treeShell.setLayout(layout);
-
-      tree = new FileTree(treeShell, HopVfs.getFileObject(projectHome), 
projectName);
-      GridData gd = new GridData(GridData.FILL_BOTH);
-      gd.horizontalSpan = 4;
-      gd.heightHint = 300;
-      gd.horizontalIndent = 10;
-      tree.setLayoutData(gd);
 
-      Label separator = new Label(treeShell, SWT.SEPARATOR | SWT.SHADOW_OUT | 
SWT.HORIZONTAL);
-      GridData gdSeparator = new GridData(SWT.FILL, SWT.CENTER, true, false);
-      gdSeparator.horizontalSpan = 4;
-      separator.setLayoutData(gdSeparator);
-
-      Button btnIncludeVariables = new Button(treeShell, SWT.CHECK);
-      btnIncludeVariables.setSelection(true);
-      btnIncludeVariables.addListener(
-          SWT.Selection, event -> 
includeVariables.set(btnIncludeVariables.getSelection()));
-      GridData gdBtnIncludeVariables = new 
GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
-      gdBtnIncludeVariables.horizontalIndent = 10;
-      btnIncludeVariables.setLayoutData(gdBtnIncludeVariables);
-      Label lblIncludeVariables = new Label(treeShell, SWT.NONE);
-      lblIncludeVariables.setText(
-          BaseMessages.getString(PKG, 
"ProjectGuiPlugin.IncludeVariables.Label"));
-      GridData gdLblIncludeVariables = new GridData(GridData.FILL_HORIZONTAL);
-      gdLblIncludeVariables.horizontalSpan = 3;
-      lblIncludeVariables.setLayoutData(gdLblIncludeVariables);
-
-      Button btnIncludeMetadata = new Button(treeShell, SWT.CHECK);
-      btnIncludeMetadata.setSelection(true);
-      btnIncludeMetadata.addListener(
-          SWT.Selection, event -> 
includeMetadata.set(btnIncludeMetadata.getSelection()));
-      GridData gdBtnIncludeMetadata = new 
GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
-      gdBtnIncludeMetadata.horizontalIndent = 10;
-      btnIncludeMetadata.setLayoutData(gdBtnIncludeMetadata);
-      Label lblIncludeMetadata = new Label(treeShell, SWT.NONE);
-      lblIncludeMetadata.setText(
-          BaseMessages.getString(PKG, 
"ProjectGuiPlugin.IncludeMetadata.Label"));
-      GridData gdLblIncludeMetadata = new GridData(GridData.FILL_HORIZONTAL);
-      gdLblIncludeMetadata.horizontalSpan = 3;
-      lblIncludeMetadata.setLayoutData(gdLblIncludeMetadata);
+      FormLayout formLayout = new FormLayout();
+      formLayout.marginWidth = PropsUi.getFormMargin();
+      formLayout.marginHeight = PropsUi.getFormMargin();
+      treeShell.setLayout(formLayout);
 
+      // Some buttons at the bottom
       Button okButton = new Button(treeShell, SWT.PUSH);
       okButton.setText(BaseMessages.getString(PKG, "System.Button.OK"));
       okButton.addListener(
@@ -1180,20 +1141,55 @@ public class ProjectsGuiPlugin {
             cancel.set(false);
             treeShell.dispose();
           });
-      GridData gdBtnOk = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
-      gdBtnOk.horizontalSpan = 2;
-      gdBtnOk.widthHint = 100;
-      okButton.setLayoutData(gdBtnOk);
-      treeShell.setDefaultButton(okButton);
 
       Button cancelButton = new Button(treeShell, SWT.PUSH);
       cancelButton.setText(BaseMessages.getString(PKG, 
"System.Button.Cancel"));
       cancelButton.addListener(SWT.Selection, event -> treeShell.dispose());
-      GridData gdBtCancel = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
-      gdBtCancel.horizontalSpan = 2;
-      gdBtCancel.widthHint = 100;
-      cancelButton.setLayoutData(gdBtCancel);
+      BaseTransformDialog.positionBottomButtons(
+          shell, new Button[] {okButton, cancelButton}, PropsUi.getMargin(), 
null);
+
+      Label separator = new Label(treeShell, SWT.SEPARATOR | SWT.HORIZONTAL);
+      separator.setLayoutData(
+          new FormDataBuilder()
+              .left()
+              .fullWidth()
+              .bottom(okButton, -2 * PropsUi.getMargin())
+              .result());
+
+      Button btnIncludeMetadata = new Button(treeShell, SWT.CHECK);
+      PropsUi.setLook(btnIncludeMetadata);
+      btnIncludeMetadata.setText(
+          BaseMessages.getString(PKG, 
"ProjectGuiPlugin.IncludeMetadata.Label"));
+      btnIncludeMetadata.setSelection(true);
+      btnIncludeMetadata.setLayoutData(
+          new FormDataBuilder().fullWidth().bottom(separator, -2 * 
PropsUi.getMargin()).result());
+      btnIncludeMetadata.addListener(
+          SWT.Selection, event -> 
includeMetadata.set(btnIncludeMetadata.getSelection()));
+
+      Button btnIncludeVariables = new Button(treeShell, SWT.CHECK);
+      PropsUi.setLook(btnIncludeVariables);
+      btnIncludeVariables.setText(
+          BaseMessages.getString(PKG, 
"ProjectGuiPlugin.IncludeVariables.Label"));
+      btnIncludeVariables.setSelection(true);
+      btnIncludeVariables.addListener(
+          SWT.Selection, event -> 
includeVariables.set(btnIncludeVariables.getSelection()));
+      btnIncludeVariables.setLayoutData(
+          new FormDataBuilder()
+              .fullWidth()
+              .bottom(btnIncludeMetadata, -PropsUi.getMargin())
+              .result());
 
+      tree = new FileTree(treeShell, HopVfs.getFileObject(projectHome), 
projectName);
+      tree.setLayoutData(
+          new FormDataBuilder()
+              .top()
+              .fullWidth()
+              .bottom(btnIncludeVariables, -PropsUi.getMargin())
+              .result());
+
+      BaseTransformDialog.setSize(treeShell);
+
+      treeShell.setDefaultButton(okButton);
       treeShell.pack();
       treeShell.open();
 
@@ -1246,24 +1242,26 @@ public class ProjectsGuiPlugin {
                   new 
SerializableMetadataProvider(hopGui.getMetadataProvider());
               String metadataJson = metadataProvider.toJson();
 
-              OutputStream outputStream = HopVfs.getOutputStream(zipFilename, 
false);
+              FileObject zipFile = HopVfs.getFileObject(zipFilename);
+              OutputStream outputStream = HopVfs.getOutputStream(zipFile, 
false);
               ZipOutputStream zos = new ZipOutputStream(outputStream);
               FileObject projectDirectory = HopVfs.getFileObject(projectHome);
               String projectHomeFolder =
                   
HopVfs.getFileObject(projectHome).getParent().getName().getURI();
 
+              // Includes selected files and dependencies
               if (!tree.getFileObjects().isEmpty()) {
                 for (FileObject fileObject : tree.getFileObjects()) {
-                  zipFile(
-                      fileObject,
-                      fileObject.getName().getURI(),
-                      zos,
-                      projectHomeFolder,
-                      zipFilename);
+                  // To prevent the zip file from including itself
+                  if (zipFile.equals(fileObject)) {
+                    continue;
+                  }
+                  monitor.subTask(fileObject.getName().getURI());
+                  zipFile(fileObject, fileObject.getName().getURI(), zos, 
projectHomeFolder);
                 }
-              } else {
-                return;
               }
+
+              // Includes config file
               zipFile(
                   HopVfs.getFileObject(
                       Const.HOP_CONFIG_FOLDER + Const.FILE_SEPARATOR + 
Const.HOP_CONFIG),
@@ -1271,21 +1269,26 @@ public class ProjectsGuiPlugin {
                       + Const.FILE_SEPARATOR
                       + Const.HOP_CONFIG,
                   zos,
-                  projectHomeFolder,
-                  zipFilename);
+                  projectHomeFolder);
+
+              // Includes variables
               if (includeVariables.get()) {
                 zipString(
                     variablesJson, "variables.json", zos, 
projectDirectory.getName().getBaseName());
               }
+
+              // Includes metadata
               if (includeMetadata.get()) {
                 zipString(
                     metadataJson, "metadata.json", zos, 
projectDirectory.getName().getBaseName());
               }
+
               zos.close();
               outputStream.close();
-              monitor.done();
             } catch (Exception e) {
               throw new InvocationTargetException(e, "Error zipping project: " 
+ e.getMessage());
+            } finally {
+              monitor.done();
             }
           };
 
@@ -1317,52 +1320,40 @@ public class ProjectsGuiPlugin {
    * @param filename destination filename
    * @param zipOutputStream zip output stream to append the file to
    * @param projectHomeParent project home folder to be stripped from the base 
path
-   * @param zipFilename name of the destination zip file
    * @throws IOException when failing to add a file to the zip
    */
   public void zipFile(
       FileObject fileToZip,
       String filename,
       ZipOutputStream zipOutputStream,
-      String projectHomeParent,
-      String zipFilename)
+      String projectHomeParent)
       throws IOException {
     if (fileToZip.isHidden()) {
       return;
     }
+
+    // Build relative filename
+    filename = filename.replace(projectHomeParent, "");
+    if (filename.startsWith("/")) {
+      filename = filename.substring(1);
+    }
+
+    zipOutputStream.putNextEntry(new ZipEntry(filename));
     if (fileToZip.isFolder()) {
-      if (filename.endsWith("/")) {
-        zipOutputStream.putNextEntry(new 
ZipEntry(filename.replaceAll(projectHomeParent, "")));
-        zipOutputStream.closeEntry();
-      } else {
-        zipOutputStream.putNextEntry(
-            new ZipEntry(filename.replaceAll(projectHomeParent, "") + "/"));
-        zipOutputStream.closeEntry();
-      }
-      FileObject[] children = fileToZip.getChildren();
-      for (FileObject childFile : children) {
-        if (childFile.equals(zipFilename)) {
-          return;
-        }
+      zipOutputStream.closeEntry();
+      for (FileObject childFile : fileToZip.getChildren()) {
         zipFile(
             childFile,
             filename + "/" + childFile.getName().getBaseName(),
             zipOutputStream,
-            projectHomeParent,
-            zipFilename);
+            projectHomeParent);
       }
-      return;
-    }
-    InputStream fis = HopVfs.getInputStream(fileToZip);
-    ZipEntry zipEntry = new ZipEntry(filename.replaceAll(projectHomeParent, 
""));
-    zipOutputStream.putNextEntry(zipEntry);
-    byte[] bytes = new byte[1024];
-    int length;
-    while ((length = fis.read(bytes)) >= 0) {
-      zipOutputStream.write(bytes, 0, length);
+    } else {
+      InputStream fis = HopVfs.getInputStream(fileToZip);
+      fis.transferTo(zipOutputStream);
+      fis.close();
+      zipOutputStream.closeEntry();
     }
-    zipOutputStream.closeEntry();
-    fis.close();
   }
 
   /**
diff --git 
a/plugins/misc/projects/src/main/resources/org/apache/hop/projects/gui/messages/messages_en_US.properties
 
b/plugins/misc/projects/src/main/resources/org/apache/hop/projects/gui/messages/messages_en_US.properties
index 79741c87a0..a420a26b7c 100644
--- 
a/plugins/misc/projects/src/main/resources/org/apache/hop/projects/gui/messages/messages_en_US.properties
+++ 
b/plugins/misc/projects/src/main/resources/org/apache/hop/projects/gui/messages/messages_en_US.properties
@@ -78,4 +78,4 @@ ProjectGuiPlugin.ZipDirectory.Error.Dialog.Header=Error
 ProjectGuiPlugin.ZipDirectory.Error.Dialog.Message=Error zipping project
 ProjectGuiPlugin.ZipDirectory.Taskname.Text=Zipping project directory...
 ProjectGuiPlugin.IncludeVariables.Label=Include variables in export
-ProjectGuiPlugin.IncludeMetadata.Label=Include Metadata in export
\ No newline at end of file
+ProjectGuiPlugin.IncludeMetadata.Label=Include metadata in export
\ No newline at end of file
diff --git a/ui/src/main/java/org/apache/hop/ui/core/widget/FileTree.java 
b/ui/src/main/java/org/apache/hop/ui/core/widget/FileTree.java
index f4919aa135..8b89eff4c0 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/widget/FileTree.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/widget/FileTree.java
@@ -36,17 +36,16 @@ import org.apache.hop.metadata.api.HopMetadataPropertyType;
 import org.apache.hop.metadata.util.ReflectionUtil;
 import org.apache.hop.pipeline.PipelineMeta;
 import org.apache.hop.pipeline.transform.TransformMeta;
+import org.apache.hop.ui.core.FormDataBuilder;
 import org.apache.hop.ui.core.PropsUi;
 import org.apache.hop.ui.core.gui.GuiResource;
 import org.apache.hop.ui.hopgui.HopGui;
 import org.apache.hop.workflow.WorkflowMeta;
 import org.apache.hop.workflow.action.ActionMeta;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.FormLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Tree;
 import org.eclipse.swt.widgets.TreeItem;
 
@@ -69,34 +68,27 @@ public class FileTree extends Composite {
     this.fileObjects = new LinkedHashSet<>();
     this.findDependencies = new AtomicBoolean(true);
 
-    GridLayout layout = new GridLayout();
-    layout.marginLeft = 0;
-    layout.marginRight = 0;
-    layout.marginTop = 0;
-    layout.marginBottom = 0;
-
-    layout.numColumns = 2;
-    this.setLayout(layout);
+    this.setLayout(new FormLayout());
     PropsUi.setLook(this);
 
-    tree = new Tree(this, SWT.CHECK | SWT.MULTI);
-    GridData gd = new GridData(GridData.FILL_BOTH | SWT.V_SCROLL);
-    gd.horizontalSpan = 2;
-    tree.setLayoutData(gd);
-
     Button btnFindDependencies = new Button(this, SWT.CHECK);
+    PropsUi.setLook(btnFindDependencies);
+    btnFindDependencies.setText(
+        BaseMessages.getString(PKG, 
"FileTreeWidget.IncludeDependencies.Label"));
     btnFindDependencies.setSelection(true);
     btnFindDependencies.addListener(
         SWT.Selection, event -> 
findDependencies.set(btnFindDependencies.getSelection()));
-    GridData gdBtnFindDependencies = new 
GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
-    gdBtnFindDependencies.verticalIndent = 10;
-    btnFindDependencies.setLayoutData(gdBtnFindDependencies);
-    Label lblFindDependencies = new Label(this, SWT.NONE);
-    lblFindDependencies.setText(
-        BaseMessages.getString(PKG, 
"FileTreeWidget.IncludeDependencies.Label"));
-    GridData gdLblFindDependencies = new GridData(GridData.FILL_HORIZONTAL);
-    gdLblFindDependencies.verticalIndent = 10;
-    lblFindDependencies.setLayoutData(gdLblFindDependencies);
+    btnFindDependencies.setLayoutData(new 
FormDataBuilder().left().fullWidth().bottom().result());
+
+    tree = new Tree(this, SWT.CHECK | SWT.MULTI | SWT.BORDER);
+    PropsUi.setLook(tree);
+    tree.setLayoutData(
+        new FormDataBuilder()
+            .top()
+            .left()
+            .right()
+            .bottom(btnFindDependencies, -PropsUi.getMargin())
+            .result());
 
     TreeItem rootItem = new TreeItem(tree, SWT.NONE);
     rootItem.setText(rootFolderName);

Reply via email to