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

mattcasters 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 ad8c53380d Issue #8315 : Offer a field dropdown for filenames accepted 
from the input stream (#8323)
ad8c53380d is described below

commit ad8c53380daf8a6ea38cb07ea68a0e5bf1893f80
Author: Bart Maertens <[email protected]>
AuthorDate: Sat Sep 12 23:05:58 2026 +0200

    Issue #8315 : Offer a field dropdown for filenames accepted from the input 
stream (#8323)
    
    Text File Input and vCard Input were the only file input transforms where 
the
    filename field was a free-text box. Both now use a CCombo filled on focus 
with
    the fields of the transform named in 'Accept filenames from transform', 
falling
    back to all previous transforms when none is selected.
    
    Two vCard Input defects surfaced while testing this and are fixed here:
    
    - VCardInputMeta listed the accept_filenames, accept_transform_name,
      accept_field, passing_through_fields and add_to_result_filenames keys in
      childKeysToIgnore, copied from JsonInputMeta which does not use them. They
      were never written to or read from the pipeline file, so the settings were
      silently dropped on save. Removing the list also exposes them as metadata
      injection keys.
    
    - VCardInput prepared its output row metadata on the first processRow(), 
which
      needs getInputRowMeta(); that is only populated after the first getRow().
      Reading filenames from the stream failed immediately. The metadata is now
      prepared after the first row is read.
    
    Adds unit tests for both defects and integration test 0111 covering the
    accepting path end to end.
---
 .../0111-vcard-input-accept-filenames.hpl          | 152 +++++++++++++++++++++
 .../datasets/golden-vcard-accept-filenames.csv     |   3 +
 .../transforms/files/vcard-accept-1.vcf            |  26 ++++
 .../transforms/files/vcard-accept-2.vcf            |  26 ++++
 .../main-0111-vcard-input-accept-filenames.hwf     |  80 +++++++++++
 .../dataset/golden-vcard-accept-filenames.json     |  32 +++++
 .../0111-vcard-input-accept-filenames UNIT.json    |  38 ++++++
 .../fileinput/text/TextFileInputDialog.java        |  40 +++++-
 .../text/messages/messages_en_US.properties        |   2 +
 .../pipeline/transforms/vcardinput/VCardInput.java |   9 +-
 .../vcardinput/VCardInputFileDialogSection.java    |  44 +++++-
 .../transforms/vcardinput/VCardInputMeta.java      |  11 +-
 .../vcardinput/messages/messages_en_US.properties  |   2 +
 .../transforms/vcardinput/VCardInputMetaTest.java  |  17 +++
 .../transforms/vcardinput/VCardInputTest.java      |  62 +++++++++
 .../src/test/resources/vcard-input-transform.xml   |   5 +
 16 files changed, 534 insertions(+), 15 deletions(-)

diff --git a/integration-tests/transforms/0111-vcard-input-accept-filenames.hpl 
b/integration-tests/transforms/0111-vcard-input-accept-filenames.hpl
new file mode 100644
index 0000000000..8c1c552019
--- /dev/null
+++ b/integration-tests/transforms/0111-vcard-input-accept-filenames.hpl
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+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.
+
+-->
+<pipeline>
+  <info>
+    <name>0111-vcard-input-accept-filenames</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description>Reads vCard files whose names arrive on the input stream 
instead of the static file list.</description>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_status>0</pipeline_status>
+    <parameters/>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <modified_user>-</modified_user>
+    <created_date>2026/09/10 12:00:00.000</created_date>
+    <modified_date>2026/09/10 12:00:00.000</modified_date>
+    <created_hop_version/>
+    <modified_hop_version/>
+  </info>
+  <order>
+    <hop>
+      <from>get filenames</from>
+      <to>read vcards</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>read vcards</from>
+      <to>validate</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>get filenames</name>
+    <type>GetFileNames</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <doNotFailIfNoFile>N</doNotFailIfNoFile>
+    <dynamic_include_subfolders>N</dynamic_include_subfolders>
+    <exclude_wildcard_Field/>
+    <file>
+      <exclude_filemask/>
+      <file_required>N</file_required>
+      <filemask>vcard-accept-.*\.vcf</filemask>
+      <include_subfolders>N</include_subfolders>
+      <name>${PROJECT_HOME}/files</name>
+    </file>
+    <filefield>N</filefield>
+    <filename_Field/>
+    <filter>
+      <filterfiletype>only_files</filterfiletype>
+    </filter>
+    <isaddresult>N</isaddresult>
+    <limit>0</limit>
+    <raiseAnExceptionIfNoFile>Y</raiseAnExceptionIfNoFile>
+    <rownum>N</rownum>
+    <rownum_field/>
+    <wildcard_Field/>
+    <attributes/>
+    <GUI>
+      <xloc>112</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>read vcards</name>
+    <type>VCardInput</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <include_filename>N</include_filename>
+    <filename_field>vcard_filename</filename_field>
+    <ignore_empty_file>Y</ignore_empty_file>
+    <do_not_fail_if_no_file>N</do_not_fail_if_no_file>
+    <encoding>UTF-8</encoding>
+    <files/>
+    <accept_filenames>Y</accept_filenames>
+    <accept_transform_name>get filenames</accept_transform_name>
+    <passing_through_fields>N</passing_through_fields>
+    <accept_field>filename</accept_field>
+    <add_to_result_filenames>N</add_to_result_filenames>
+    <field>
+      <hop_field>fn</hop_field>
+      <property>fn</property>
+      <parameter_types/>
+    </field>
+    <field>
+      <hop_field>uid</hop_field>
+      <property>uid</property>
+      <parameter_types/>
+    </field>
+    <field>
+      <hop_field>email</hop_field>
+      <property>email</property>
+      <parameter_types>INTERNET</parameter_types>
+    </field>
+    <attributes/>
+    <GUI>
+      <xloc>288</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>validate</name>
+    <type>Dummy</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+    <GUI>
+      <xloc>464</xloc>
+      <yloc>96</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>
diff --git 
a/integration-tests/transforms/datasets/golden-vcard-accept-filenames.csv 
b/integration-tests/transforms/datasets/golden-vcard-accept-filenames.csv
new file mode 100644
index 0000000000..a24a5bda64
--- /dev/null
+++ b/integration-tests/transforms/datasets/golden-vcard-accept-filenames.csv
@@ -0,0 +1,3 @@
+fn,uid,email
+Ada Lovelace,vcard-accept-001,[email protected]
+Alan Turing,vcard-accept-002,[email protected]
diff --git a/integration-tests/transforms/files/vcard-accept-1.vcf 
b/integration-tests/transforms/files/vcard-accept-1.vcf
new file mode 100644
index 0000000000..c15fb29b88
--- /dev/null
+++ b/integration-tests/transforms/files/vcard-accept-1.vcf
@@ -0,0 +1,26 @@
+#
+#
+# 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.
+#
+#
+#
+BEGIN:VCARD
+VERSION:3.0
+FN:Ada Lovelace
+N:Lovelace;Ada;;;
+UID:vcard-accept-001
+EMAIL;TYPE=INTERNET:[email protected]
+END:VCARD
diff --git a/integration-tests/transforms/files/vcard-accept-2.vcf 
b/integration-tests/transforms/files/vcard-accept-2.vcf
new file mode 100644
index 0000000000..addfa82917
--- /dev/null
+++ b/integration-tests/transforms/files/vcard-accept-2.vcf
@@ -0,0 +1,26 @@
+#
+#
+# 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.
+#
+#
+#
+BEGIN:VCARD
+VERSION:3.0
+FN:Alan Turing
+N:Turing;Alan;;;
+UID:vcard-accept-002
+EMAIL;TYPE=INTERNET:[email protected]
+END:VCARD
diff --git 
a/integration-tests/transforms/main-0111-vcard-input-accept-filenames.hwf 
b/integration-tests/transforms/main-0111-vcard-input-accept-filenames.hwf
new file mode 100644
index 0000000000..03bc9dbe4f
--- /dev/null
+++ b/integration-tests/transforms/main-0111-vcard-input-accept-filenames.hwf
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+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.
+
+-->
+<workflow>
+  <name>main-0111-vcard-input-accept-filenames</name>
+  <name_sync_with_filename>Y</name_sync_with_filename>
+  <description/>
+  <extended_description/>
+  <workflow_version/>
+  <created_user>-</created_user>
+  <created_date>2026/06/12 12:00:00.000</created_date>
+  <modified_user>-</modified_user>
+  <modified_date>2026/06/12 12:00:00.000</modified_date>
+  <parameters>
+    </parameters>
+  <actions>
+    <action>
+      <name>Start</name>
+      <description/>
+      <type>SPECIAL</type>
+      <attributes/>
+      <DayOfMonth>1</DayOfMonth>
+      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
+      <hour>12</hour>
+      <intervalMinutes>60</intervalMinutes>
+      <intervalSeconds>0</intervalSeconds>
+      <minutes>0</minutes>
+      <repeat>N</repeat>
+      <schedulerType>0</schedulerType>
+      <weekDay>1</weekDay>
+      <parallel>N</parallel>
+      <xloc>80</xloc>
+      <yloc>64</yloc>
+      <attributes_hac/>
+    </action>
+    <action>
+      <name>0111-vcard-input-accept-filenames UNIT</name>
+      <description/>
+      <type>RunPipelineTests</type>
+      <attributes/>
+      <test_names>
+        <test_name>
+          <name>0111-vcard-input-accept-filenames UNIT</name>
+        </test_name>
+      </test_names>
+      <parallel>N</parallel>
+      <xloc>272</xloc>
+      <yloc>64</yloc>
+      <attributes_hac/>
+    </action>
+  </actions>
+  <hops>
+    <hop>
+      <from>Start</from>
+      <to>0111-vcard-input-accept-filenames UNIT</to>
+      <enabled>Y</enabled>
+      <evaluation>Y</evaluation>
+      <unconditional>Y</unconditional>
+    </hop>
+  </hops>
+  <notepads>
+  </notepads>
+  <attributes/>
+</workflow>
diff --git 
a/integration-tests/transforms/metadata/dataset/golden-vcard-accept-filenames.json
 
b/integration-tests/transforms/metadata/dataset/golden-vcard-accept-filenames.json
new file mode 100644
index 0000000000..7fad3ddbd1
--- /dev/null
+++ 
b/integration-tests/transforms/metadata/dataset/golden-vcard-accept-filenames.json
@@ -0,0 +1,32 @@
+{
+  "base_filename": "golden-vcard-accept-filenames.csv",
+  "name": "golden-vcard-accept-filenames",
+  "description": "",
+  "dataset_fields": [
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "fn",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "uid",
+      "field_format": ""
+    },
+    {
+      "field_comment": "",
+      "field_length": -1,
+      "field_type": 2,
+      "field_precision": -1,
+      "field_name": "email",
+      "field_format": ""
+    }
+  ],
+  "folder_name": ""
+}
diff --git 
a/integration-tests/transforms/metadata/unit-test/0111-vcard-input-accept-filenames
 UNIT.json 
b/integration-tests/transforms/metadata/unit-test/0111-vcard-input-accept-filenames
 UNIT.json
new file mode 100644
index 0000000000..7d1228df8a
--- /dev/null
+++ 
b/integration-tests/transforms/metadata/unit-test/0111-vcard-input-accept-filenames
 UNIT.json       
@@ -0,0 +1,38 @@
+{
+  "database_replacements": [],
+  "autoOpening": true,
+  "description": "",
+  "persist_filename": "",
+  "test_type": "UNIT_TEST",
+  "variableValues": [],
+  "basePath": "${HOP_UNIT_TESTS_FOLDER}",
+  "golden_data_sets": [
+    {
+      "field_mappings": [
+        {
+          "transform_field": "fn",
+          "data_set_field": "fn"
+        },
+        {
+          "transform_field": "uid",
+          "data_set_field": "uid"
+        },
+        {
+          "transform_field": "email",
+          "data_set_field": "email"
+        }
+      ],
+      "field_order": [
+        "fn",
+        "uid",
+        "email"
+      ],
+      "data_set_name": "golden-vcard-accept-filenames",
+      "transform_name": "validate"
+    }
+  ],
+  "input_data_sets": [],
+  "name": "0111-vcard-input-accept-filenames UNIT",
+  "trans_test_tweaks": [],
+  "pipeline_filename": "./0111-vcard-input-accept-filenames.hpl"
+}
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 bba43343f6..08bfc4b1bc 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
@@ -139,7 +139,7 @@ public class TextFileInputDialog extends BaseTransformDialog
   private Button wPassThruFields;
 
   private Label wlAccField;
-  private Text wAccField;
+  private CCombo wAccField;
 
   private Label wlAccTransform;
   private CCombo wAccTransform;
@@ -782,7 +782,8 @@ public class TextFileInputDialog extends BaseTransformDialog
     fdlAccField.left = new FormAttachment(0, 0);
     fdlAccField.right = new FormAttachment(middle, -margin);
     wlAccField.setLayoutData(fdlAccField);
-    wAccField = new Text(gAccepting, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
+    wAccField = new CCombo(gAccepting, SWT.BORDER | SWT.READ_ONLY);
+    wAccField.setEditable(true);
     wAccField.setToolTipText(
         BaseMessages.getString(PKG, 
"TextFileInputDialog.AcceptField.Tooltip"));
     PropsUi.setLook(wAccField);
@@ -791,6 +792,15 @@ public class TextFileInputDialog extends 
BaseTransformDialog
     fdAccField.left = new FormAttachment(middle, 0);
     fdAccField.right = new FormAttachment(100, 0);
     wAccField.setLayoutData(fdAccField);
+    wAccField.addListener(
+        SWT.FocusIn,
+        e -> {
+          Cursor busy = new Cursor(shell.getDisplay(), SWT.CURSOR_WAIT);
+          shell.setCursor(busy);
+          setAcceptField();
+          shell.setCursor(null);
+          busy.dispose();
+        });
 
     // Fill in the source transforms...
     List<TransformMeta> prevTransforms =
@@ -2239,6 +2249,32 @@ public class TextFileInputDialog extends 
BaseTransformDialog
     }
   }
 
+  /**
+   * Fill the filename field combo with the fields of the transform we accept 
filenames from. When
+   * no transform has been selected yet we fall back to the fields of all 
previous transforms.
+   */
+  private void setAcceptField() {
+    try {
+      String acceptTransformName = wAccTransform.getText();
+      IRowMeta r =
+          Utils.isEmpty(acceptTransformName)
+              ? pipelineMeta.getPrevTransformFields(variables, transformName)
+              : pipelineMeta.getTransformFields(variables, 
acceptTransformName);
+      // setItems() leaves the text of an editable combo alone, so the 
configured field survives
+      // the refresh and simply opening the dropdown does not mark the dialog 
as changed.
+      //
+      wAccField.setItems(r == null ? new String[0] : r.getFieldNames());
+    } catch (HopException e) {
+      new ErrorDialog(
+          shell,
+          BaseMessages.getString(
+              PKG, 
"TextFileInputDialog.ErrorDialog.UnableToGetInputFields.Title"),
+          BaseMessages.getString(
+              PKG, 
"TextFileInputDialog.ErrorDialog.UnableToGetInputFields.Message"),
+          e);
+    }
+  }
+
   public void setFlags() {
     boolean accept = wAccFilenames.getSelection();
     wlPassThruFields.setEnabled(accept);
diff --git 
a/plugins/transforms/textfile/src/main/resources/org/apache/hop/pipeline/transforms/fileinput/text/messages/messages_en_US.properties
 
b/plugins/transforms/textfile/src/main/resources/org/apache/hop/pipeline/transforms/fileinput/text/messages/messages_en_US.properties
index 51c2c40f82..799edaaa24 100644
--- 
a/plugins/transforms/textfile/src/main/resources/org/apache/hop/pipeline/transforms/fileinput/text/messages/messages_en_US.properties
+++ 
b/plugins/transforms/textfile/src/main/resources/org/apache/hop/pipeline/transforms/fileinput/text/messages/messages_en_US.properties
@@ -155,6 +155,8 @@ TextFileInput.Log.Warning=WARNING
 TextFileInput.Name=Text file input
 TextFileInputDialog.AcceptField.Label=Field in the input to use as filename
 TextFileInputDialog.AcceptField.Tooltip=Specify the field in the input rows to 
use as filename
+TextFileInputDialog.ErrorDialog.UnableToGetInputFields.Message=Unable to get 
the input fields for this transform\!
+TextFileInputDialog.ErrorDialog.UnableToGetInputFields.Title=Error
 TextFileInputDialog.AcceptFilenames.Label=Accept filenames from previous 
transform
 TextFileInputDialog.AcceptFilenames.Tooltip=Enable this if you define the 
filenames in another transform\nand want this transform to accept those 
filenames
 TextFileInputDialog.AcceptingGroup.Label=Accept filenames from previous 
transforms
diff --git 
a/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInput.java
 
b/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInput.java
index 0d3529b485..682350853b 100644
--- 
a/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInput.java
+++ 
b/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInput.java
@@ -74,7 +74,10 @@ public class VCardInput extends 
BaseTransform<VCardInputMeta, VCardInputData> {
 
   @Override
   public boolean processRow() throws HopException {
-    if (first) {
+    // When we accept filenames from an incoming stream the input row metadata 
only becomes
+    // available after the first getRow(), so the output row metadata is 
prepared there instead.
+    //
+    if (first && !meta.getFileInput().isAcceptingFilenames()) {
       first = false;
       prepareOutputRowMeta();
     }
@@ -117,6 +120,10 @@ public class VCardInput extends 
BaseTransform<VCardInputMeta, VCardInputData> {
         setOutputDone();
         return false;
       }
+      if (first) {
+        first = false;
+        prepareOutputRowMeta();
+      }
       data.currentInputRow = meta.getFileInput().isPassingThruFields() ? row : 
null;
       String path = resolve(getInputRowMeta().getString(row, 
data.acceptFieldIndex));
       loadCardsFromPath(path);
diff --git 
a/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputFileDialogSection.java
 
b/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputFileDialogSection.java
index 1a5df9bb94..cce33ae972 100644
--- 
a/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputFileDialogSection.java
+++ 
b/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputFileDialogSection.java
@@ -19,8 +19,11 @@ package org.apache.hop.pipeline.transforms.vcardinput;
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.hop.core.Const;
+import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.fileinput.FileInputList;
 import org.apache.hop.core.fileinput.InputFile;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.util.Utils;
 import org.apache.hop.core.variables.IVariables;
 import org.apache.hop.i18n.BaseMessages;
 import org.apache.hop.pipeline.PipelineMeta;
@@ -37,6 +40,7 @@ import org.eclipse.swt.custom.CCombo;
 import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Cursor;
 import org.eclipse.swt.layout.FormAttachment;
 import org.eclipse.swt.layout.FormData;
 import org.eclipse.swt.layout.FormLayout;
@@ -79,7 +83,7 @@ public final class VCardInputFileDialogSection {
   public Button wAccFilenames;
   public Button wPassThruFields;
   public CCombo wAccTransform;
-  public Text wAccField;
+  public CCombo wAccField;
   public Button wIncludeFilename;
   public Text wIncludeFilenameField;
   public TextVar wEncoding;
@@ -298,7 +302,8 @@ public final class VCardInputFileDialogSection {
     fdlAccField.right = new FormAttachment(middle, -margin);
     wlAccField.setLayoutData(fdlAccField);
 
-    wAccField = new Text(gAccepting, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
+    wAccField = new CCombo(gAccepting, SWT.BORDER | SWT.READ_ONLY);
+    wAccField.setEditable(true);
     wAccField.setToolTipText(
         BaseMessages.getString(PKG, 
"VCardInputFileDialog.AcceptField.Tooltip"));
     PropsUi.setLook(wAccField);
@@ -308,6 +313,15 @@ public final class VCardInputFileDialogSection {
     fdAccField.left = new FormAttachment(middle, 0);
     fdAccField.right = new FormAttachment(100, 0);
     wAccField.setLayoutData(fdAccField);
+    wAccField.addListener(
+        SWT.FocusIn,
+        e -> {
+          Cursor busy = new Cursor(shell.getDisplay(), SWT.CURSOR_WAIT);
+          shell.setCursor(busy);
+          setAcceptField();
+          shell.setCursor(null);
+          busy.dispose();
+        });
 
     TransformMeta thisTransform = pipelineMeta.findTransform(transformName);
     if (thisTransform != null) {
@@ -569,6 +583,32 @@ public final class VCardInputFileDialogSection {
         });
   }
 
+  /**
+   * Fill the filename field combo with the fields of the transform we accept 
filenames from. When
+   * no transform has been selected yet we fall back to the fields of all 
previous transforms.
+   */
+  private void setAcceptField() {
+    try {
+      String acceptTransformName = wAccTransform.getText();
+      IRowMeta r =
+          Utils.isEmpty(acceptTransformName)
+              ? pipelineMeta.getPrevTransformFields(variables, transformName)
+              : pipelineMeta.getTransformFields(variables, 
acceptTransformName);
+      // setItems() leaves the text of an editable combo alone, so the 
configured field survives
+      // the refresh and simply opening the dropdown does not mark the dialog 
as changed.
+      //
+      wAccField.setItems(r == null ? new String[0] : r.getFieldNames());
+    } catch (HopException e) {
+      new ErrorDialog(
+          shell,
+          BaseMessages.getString(
+              PKG, 
"VCardInputFileDialog.ErrorDialog.UnableToGetInputFields.Title"),
+          BaseMessages.getString(
+              PKG, 
"VCardInputFileDialog.ErrorDialog.UnableToGetInputFields.Message"),
+          e);
+    }
+  }
+
   private void activeIncludeFilename() {
     boolean include = wIncludeFilename.getSelection();
     wlIncludeFilenameField.setEnabled(include);
diff --git 
a/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputMeta.java
 
b/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputMeta.java
index 86c34baa04..c931a9640d 100644
--- 
a/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputMeta.java
+++ 
b/plugins/transforms/vcard/src/main/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputMeta.java
@@ -75,16 +75,7 @@ public class VCardInputMeta extends 
BaseTransformMeta<VCardInput, VCardInputData
   @HopMetadataProperty(key = "encoding")
   private String encoding;
 
-  @HopMetadataProperty(
-      key = "file",
-      inline = true,
-      childKeysToIgnore = {
-        "accept_filenames",
-        "accept_transform_name",
-        "passing_through_fields",
-        "accept_field",
-        "add_to_result_filenames",
-      })
+  @HopMetadataProperty(key = "file", inline = true)
   private BaseFileInput fileInput;
 
   @HopMetadataProperty(key = "field")
diff --git 
a/plugins/transforms/vcard/src/main/resources/org/apache/hop/pipeline/transforms/vcardinput/messages/messages_en_US.properties
 
b/plugins/transforms/vcard/src/main/resources/org/apache/hop/pipeline/transforms/vcardinput/messages/messages_en_US.properties
index ed021f065b..ea0bc558e6 100644
--- 
a/plugins/transforms/vcard/src/main/resources/org/apache/hop/pipeline/transforms/vcardinput/messages/messages_en_US.properties
+++ 
b/plugins/transforms/vcard/src/main/resources/org/apache/hop/pipeline/transforms/vcardinput/messages/messages_en_US.properties
@@ -66,6 +66,8 @@ VCardInputFileDialog.AcceptTransform.Label=Transform to read 
from
 VCardInputFileDialog.AcceptTransform.Tooltip=The transform to read filenames 
from.
 VCardInputFileDialog.AcceptField.Label=Filename field
 VCardInputFileDialog.AcceptField.Tooltip=The field in the input stream that 
contains the filename.
+VCardInputFileDialog.ErrorDialog.UnableToGetInputFields.Message=Unable to get 
the input fields for this transform\!
+VCardInputFileDialog.ErrorDialog.UnableToGetInputFields.Title=Error
 VCardInputFileDialog.PassThruFields.Label=Pass through fields from source 
transform
 VCardInputFileDialog.PassThruFields.Tooltip=Copy all fields from the transform 
that provides the filename.
 VCardInputFileDialog.OptionsGroup.Label=Options
diff --git 
a/plugins/transforms/vcard/src/test/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputMetaTest.java
 
b/plugins/transforms/vcard/src/test/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputMetaTest.java
index 1bee05cfa6..f8689bd46c 100644
--- 
a/plugins/transforms/vcard/src/test/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputMetaTest.java
+++ 
b/plugins/transforms/vcard/src/test/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputMetaTest.java
@@ -17,6 +17,7 @@
 package org.apache.hop.pipeline.transforms.vcardinput;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import org.apache.hop.pipeline.transform.TransformSerializationTestUtil;
 import org.junit.jupiter.api.Test;
@@ -32,4 +33,20 @@ class VCardInputMetaTest {
     assertEquals("fn", meta.getFieldMappings().get(0).getHopField());
     assertEquals(1, meta.getFileInput().getInputFiles().size());
   }
+
+  /**
+   * The settings for reading filenames from an incoming stream used to be 
excluded from
+   * serialization, so they silently disappeared when a pipeline was saved.
+   */
+  @Test
+  void testSerializationOfAcceptingFilenames() throws Exception {
+    VCardInputMeta meta =
+        TransformSerializationTestUtil.testSerialization(
+            "/vcard-input-transform.xml", VCardInputMeta.class);
+    assertTrue(meta.getFileInput().isAcceptingFilenames());
+    assertEquals("get filenames", 
meta.getFileInput().getAcceptingTransformName());
+    assertEquals("filename", meta.getFileInput().getAcceptingField());
+    assertTrue(meta.getFileInput().isPassingThruFields());
+    assertTrue(meta.getFileInput().isAddingResult());
+  }
 }
diff --git 
a/plugins/transforms/vcard/src/test/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputTest.java
 
b/plugins/transforms/vcard/src/test/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputTest.java
index 83ac523e9f..c965cf73ec 100644
--- 
a/plugins/transforms/vcard/src/test/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputTest.java
+++ 
b/plugins/transforms/vcard/src/test/java/org/apache/hop/pipeline/transforms/vcardinput/VCardInputTest.java
@@ -28,11 +28,14 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
+import org.apache.hop.core.BlockingRowSet;
 import org.apache.hop.core.HopEnvironment;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.fileinput.InputFile;
 import org.apache.hop.core.logging.ILoggingObject;
 import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.RowMeta;
+import org.apache.hop.core.row.value.ValueMetaString;
 import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
 import org.apache.hop.pipeline.transform.RowAdapter;
 import org.apache.hop.pipeline.transforms.mock.TransformMockHelper;
@@ -110,6 +113,65 @@ class VCardInputTest {
     assertEquals(0, transform.getErrors());
   }
 
+  /**
+   * The output row metadata is built from the incoming row metadata, which 
only becomes available
+   * after the first getRow(). Preparing it any earlier fails with "This 
transform is not receiving
+   * rows from a previous transform".
+   */
+  @Test
+  void readsFilesNamedByAnIncomingField(@TempDir Path tempDir) throws 
Exception {
+    Path first = tempDir.resolve("first.vcf");
+    Path second = tempDir.resolve("second.vcf");
+    writeVcard(first, "Contact A");
+    writeVcard(second, "Contact B");
+
+    VCardInputMeta meta = new VCardInputMeta();
+    meta.setDoNotFailIfNoFile(false);
+    meta.setIgnoringEmptyFile(true);
+    meta.getFieldMappings().add(new VCardFieldMapping(VCardPropertyType.FN, 
"fn"));
+    meta.getFileInput().setAcceptingFilenames(true);
+    meta.getFileInput().setAcceptingTransformName("filenames");
+    meta.getFileInput().setAcceptingField("filename");
+
+    VCardInputData data = new VCardInputData();
+    VCardInput transform =
+        new VCardInput(
+            mockHelper.transformMeta, meta, data, 0, mockHelper.pipelineMeta, 
mockHelper.pipeline);
+    transform.addRowListener(
+        new RowAdapter() {
+          @Override
+          public void rowWrittenEvent(IRowMeta rowMeta, Object[] row) {
+            captured.add(row);
+          }
+        });
+
+    // Deliberately no setInputRowMeta() here: the transform has to pick the 
row metadata up from
+    // the first row it reads, exactly like it does in a running pipeline.
+    //
+    IRowMeta inputRowMeta = new RowMeta();
+    inputRowMeta.addValueMeta(new ValueMetaString("filename"));
+    BlockingRowSet rowSet = new BlockingRowSet(10);
+    rowSet.putRow(inputRowMeta, new Object[] 
{first.toAbsolutePath().toString()});
+    rowSet.putRow(inputRowMeta, new Object[] 
{second.toAbsolutePath().toString()});
+    rowSet.setDone();
+    transform.addRowSetToInputRowSets(rowSet);
+
+    assertTrue(transform.init());
+    int iterations = 0;
+    while (transform.processRow()) {
+      if (++iterations > 10) {
+        break;
+      }
+    }
+
+    assertEquals(0, transform.getErrors());
+    assertEquals(2, captured.size(), "expected one row per filename on the 
input stream");
+    int fnIndex = data.outputRowMeta.indexOfValue("fn");
+    Set<String> names =
+        captured.stream().map(row -> (String) 
row[fnIndex]).collect(Collectors.toSet());
+    assertEquals(Set.of("Contact A", "Contact B"), names);
+  }
+
   private static void writeVcard(Path path, String fullName) throws Exception {
     String vcard =
         """
diff --git 
a/plugins/transforms/vcard/src/test/resources/vcard-input-transform.xml 
b/plugins/transforms/vcard/src/test/resources/vcard-input-transform.xml
index 68f73e3373..d80b3eb625 100644
--- a/plugins/transforms/vcard/src/test/resources/vcard-input-transform.xml
+++ b/plugins/transforms/vcard/src/test/resources/vcard-input-transform.xml
@@ -22,6 +22,11 @@
     <ignore_empty_file>Y</ignore_empty_file>
     <do_not_fail_if_no_file>Y</do_not_fail_if_no_file>
     <encoding>UTF-8</encoding>
+    <accept_filenames>Y</accept_filenames>
+    <accept_transform_name>get filenames</accept_transform_name>
+    <passing_through_fields>Y</passing_through_fields>
+    <accept_field>filename</accept_field>
+    <add_to_result_filenames>Y</add_to_result_filenames>
     <files>
         <file>
             <name>${PROJECT_HOME}/files/vcard-input-sample.vcf</name>

Reply via email to