This is an automated email from the ASF dual-hosted git repository.
bamaer 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 6991014ec7 Issue #5275 : Add an Open button to dialogs that reference
a pipeline or workflow (#8697)
6991014ec7 is described below
commit 6991014ec7374b8441591ea53ae2aab44b78a9db
Author: Matt Casters <[email protected]>
AuthorDate: Thu Oct 1 09:16:59 2026 +0200
Issue #5275 : Add an Open button to dialogs that reference a pipeline or
workflow (#8697)
---
.../hop/workflow/actions/repeat/RepeatDialog.java | 24 ++-
.../eventhubs/listen/AzureListenerDialog.java | 24 ++-
.../kafka/consumer/KafkaConsumerInputDialog.java | 26 ++-
.../transforms/mapping/SimpleMappingDialog.java | 25 ++-
.../multimapping/MultiMappingDialog.java | 24 ++-
.../transforms/metainject/MetaInjectDialog.java | 25 ++-
.../pipelineexecutor/PipelineExecutorDialog.java | 27 ++-
.../workflowexecutor/WorkflowExecutorDialog.java | 27 ++-
.../hop/ui/hopgui/file/ReferencedFileOpener.java | 186 +++++++++++++++++++++
.../hop/ui/workflow/actions/ActionBaseDialog.java | 26 ++-
.../hopgui/file/messages/messages_en_US.properties | 7 +
.../ui/hopgui/file/ReferencedFileOpenerTest.java | 69 ++++++++
12 files changed, 469 insertions(+), 21 deletions(-)
diff --git
a/plugins/actions/repeat/src/main/java/org/apache/hop/workflow/actions/repeat/RepeatDialog.java
b/plugins/actions/repeat/src/main/java/org/apache/hop/workflow/actions/repeat/RepeatDialog.java
index 028cf506f4..14b54ad2f4 100644
---
a/plugins/actions/repeat/src/main/java/org/apache/hop/workflow/actions/repeat/RepeatDialog.java
+++
b/plugins/actions/repeat/src/main/java/org/apache/hop/workflow/actions/repeat/RepeatDialog.java
@@ -34,6 +34,7 @@ import org.apache.hop.ui.core.widget.ColumnInfo;
import org.apache.hop.ui.core.widget.ComboVar;
import org.apache.hop.ui.core.widget.TableView;
import org.apache.hop.ui.core.widget.TextVar;
+import org.apache.hop.ui.hopgui.file.ReferencedFileOpener;
import org.apache.hop.ui.hopgui.file.pipeline.HopPipelineFileType;
import org.apache.hop.ui.hopgui.file.workflow.HopWorkflowFileType;
import org.apache.hop.ui.workflow.action.ActionDialog;
@@ -125,11 +126,19 @@ public class RepeatDialog extends ActionDialog {
wbbFilename.setLayoutData(fdbFilename);
wbbFilename.addListener(SWT.Selection, e -> browseForFile());
+ Button wbOpen = new Button(shell, SWT.PUSH);
+ ReferencedFileOpener.configureOpenButton(wbOpen);
+ FormData fdOpen = new FormData();
+ fdOpen.right = new FormAttachment(wbbFilename, -margin);
+ fdOpen.top = new FormAttachment(wlFilename, 0, SWT.CENTER);
+ wbOpen.setLayoutData(fdOpen);
+ wbOpen.addListener(SWT.Selection, e -> openReferencedFile());
+
wFilename = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT |
SWT.BORDER);
PropsUi.setLook(wFilename);
FormData fdFilename = new FormData();
fdFilename.left = new FormAttachment(middle, 0);
- fdFilename.right = new FormAttachment(wbbFilename, -margin);
+ fdFilename.right = new FormAttachment(wbOpen, -margin);
fdFilename.top = new FormAttachment(wlFilename, 0, SWT.CENTER);
wFilename.setLayoutData(fdFilename);
lastControl = wFilename;
@@ -566,6 +575,19 @@ public class RepeatDialog extends ActionDialog {
action.setChanged();
}
+ private void openReferencedFile() {
+ ReferencedFileOpener.openFromDialog(
+ shell,
+ variables,
+ wFilename.getText(),
+ ReferencedFileOpener.isDialogModified(
+ action.hasChanged(), wFilename.getText(), action.getFilename()),
+ () -> {
+ ok();
+ return isDisposed() ? action.getFilename() : null;
+ });
+ }
+
private void ok() {
if (Utils.isEmpty(wName.getText())) {
MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
diff --git
a/plugins/tech/azure/src/main/java/org/apache/hop/pipeline/transforms/eventhubs/listen/AzureListenerDialog.java
b/plugins/tech/azure/src/main/java/org/apache/hop/pipeline/transforms/eventhubs/listen/AzureListenerDialog.java
index 4e7e8a322a..687d33911f 100644
---
a/plugins/tech/azure/src/main/java/org/apache/hop/pipeline/transforms/eventhubs/listen/AzureListenerDialog.java
+++
b/plugins/tech/azure/src/main/java/org/apache/hop/pipeline/transforms/eventhubs/listen/AzureListenerDialog.java
@@ -29,6 +29,7 @@ import org.apache.hop.ui.core.dialog.EnterSelectionDialog;
import org.apache.hop.ui.core.dialog.ErrorDialog;
import org.apache.hop.ui.core.widget.TextVar;
import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.ReferencedFileOpener;
import org.apache.hop.ui.hopgui.file.pipeline.HopPipelineFileType;
import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
import org.eclipse.swt.SWT;
@@ -412,12 +413,19 @@ public class AzureListenerDialog extends
BaseTransformDialog {
fdbBatchPipeline.right = new FormAttachment(100, -margin);
fdbBatchPipeline.top = new FormAttachment(wlBatchPipeline, 0, SWT.CENTER);
wbBatchPipeline.setLayoutData(fdbBatchPipeline);
+ Button wbOpen = new Button(wContent, SWT.PUSH);
+ ReferencedFileOpener.configureOpenButton(wbOpen);
+ FormData fdOpen = new FormData();
+ fdOpen.right = new FormAttachment(wbBatchPipeline, -margin);
+ fdOpen.top = new FormAttachment(wlBatchPipeline, 0, SWT.CENTER);
+ wbOpen.setLayoutData(fdOpen);
+ wbOpen.addListener(SWT.Selection, e -> openReferencedFile());
wBatchPipeline = new TextVar(variables, wContent, SWT.SINGLE | SWT.LEFT |
SWT.BORDER);
PropsUi.setLook(wBatchPipeline);
wBatchPipeline.addModifyListener(lsMod);
FormData fdBatchPipeline = new FormData();
fdBatchPipeline.left = new FormAttachment(middle, 0);
- fdBatchPipeline.right = new FormAttachment(wbBatchPipeline, -margin);
+ fdBatchPipeline.right = new FormAttachment(wbOpen, -margin);
fdBatchPipeline.top = new FormAttachment(wlBatchPipeline, 0, SWT.CENTER);
wBatchPipeline.setLayoutData(fdBatchPipeline);
lastControl = wBatchPipeline;
@@ -501,12 +509,26 @@ public class AzureListenerDialog extends
BaseTransformDialog {
sc.setMinHeight(bounds.height);
getData();
+ input.setChanged(changed);
focusTransformName();
BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel());
return transformName;
}
+ private void openReferencedFile() {
+ ReferencedFileOpener.openFromDialog(
+ shell,
+ variables,
+ wBatchPipeline.getText(),
+ ReferencedFileOpener.isDialogModified(
+ input.hasChanged(), wBatchPipeline.getText(),
input.getBatchPipeline()),
+ () -> {
+ ok();
+ return isDisposed() ? input.getBatchPipeline() : null;
+ });
+ }
+
private void browseForPipeline() {
HopPipelineFileType<PipelineMeta> type =
HopGui.getExplorerPerspective().getPipelineFileType();
diff --git
a/plugins/transforms/kafka/src/main/java/org/apache/hop/pipeline/transforms/kafka/consumer/KafkaConsumerInputDialog.java
b/plugins/transforms/kafka/src/main/java/org/apache/hop/pipeline/transforms/kafka/consumer/KafkaConsumerInputDialog.java
index fc3a9f29d0..65bfc0504b 100644
---
a/plugins/transforms/kafka/src/main/java/org/apache/hop/pipeline/transforms/kafka/consumer/KafkaConsumerInputDialog.java
+++
b/plugins/transforms/kafka/src/main/java/org/apache/hop/pipeline/transforms/kafka/consumer/KafkaConsumerInputDialog.java
@@ -56,6 +56,7 @@ import org.apache.hop.ui.core.widget.MetaSelectionLine;
import org.apache.hop.ui.core.widget.TableView;
import org.apache.hop.ui.core.widget.TextVar;
import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.ReferencedFileOpener;
import org.apache.hop.ui.hopgui.file.pipeline.HopPipelineFileType;
import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
import org.apache.kafka.clients.consumer.ConsumerConfig;
@@ -199,11 +200,20 @@ public class KafkaConsumerInputDialog extends
BaseTransformDialog {
true);
});
+ Button wbOpen = new Button(shell, SWT.PUSH);
+ ReferencedFileOpener.configureOpenButton(wbOpen);
+ FormData fdOpen = new FormData();
+ fdOpen.right = new FormAttachment(wbFilename, -margin);
+ fdOpen.top = new FormAttachment(wlFilename, 0, SWT.CENTER);
+ wbOpen.setLayoutData(fdOpen);
+ wbOpen.addListener(SWT.Selection, e -> openReferencedFile());
+
wFilename = new TextVar(variables, shell, SWT.SINGLE | SWT.BORDER |
SWT.LEFT);
PropsUi.setLook(wFilename);
+ wFilename.addModifyListener(lsMod);
FormData fdFilename = new FormData();
fdFilename.left = new FormAttachment(wlFilename, margin);
- fdFilename.right = new FormAttachment(wbFilename, -PropsUi.getMargin());
+ fdFilename.right = new FormAttachment(wbOpen, -PropsUi.getMargin());
fdFilename.top = new FormAttachment(wlFilename, 0, SWT.CENTER);
wFilename.setLayoutData(fdFilename);
@@ -263,6 +273,7 @@ public class KafkaConsumerInputDialog extends
BaseTransformDialog {
createAdditionalTabs();
getData();
+ meta.setChanged(changed);
wTabFolder.setSelection(0);
focusTransformName();
BaseDialog.defaultShellHandling(shell, c -> ok(), c -> cancel());
@@ -975,6 +986,19 @@ public class KafkaConsumerInputDialog extends
BaseTransformDialog {
.toArray();
}
+ private void openReferencedFile() {
+ ReferencedFileOpener.openFromDialog(
+ shell,
+ variables,
+ wFilename.getText(),
+ ReferencedFileOpener.isDialogModified(
+ meta.hasChanged(), wFilename.getText(), meta.getFilename()),
+ () -> {
+ ok();
+ return isDisposed() ? meta.getFilename() : null;
+ });
+ }
+
protected void createNewKafkaPipeline() {
PipelineMeta kafkaPipelineMeta = createSubPipelineMeta();
diff --git
a/plugins/transforms/mapping/src/main/java/org/apache/hop/pipeline/transforms/mapping/SimpleMappingDialog.java
b/plugins/transforms/mapping/src/main/java/org/apache/hop/pipeline/transforms/mapping/SimpleMappingDialog.java
index 855f84e485..4e5b7944bf 100644
---
a/plugins/transforms/mapping/src/main/java/org/apache/hop/pipeline/transforms/mapping/SimpleMappingDialog.java
+++
b/plugins/transforms/mapping/src/main/java/org/apache/hop/pipeline/transforms/mapping/SimpleMappingDialog.java
@@ -45,6 +45,7 @@ import org.apache.hop.ui.core.widget.ColumnsResizer;
import org.apache.hop.ui.core.widget.ComboVar;
import org.apache.hop.ui.core.widget.TableView;
import org.apache.hop.ui.core.widget.TextVar;
+import org.apache.hop.ui.hopgui.file.ReferencedFileOpener;
import org.apache.hop.ui.hopgui.file.pipeline.HopPipelineFileType;
import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
import org.apache.hop.ui.pipeline.transform.ITableItemInsertListener;
@@ -191,12 +192,21 @@ public class SimpleMappingDialog extends
BaseTransformDialog {
wbBrowse.setLayoutData(fdBrowse);
wbBrowse.addListener(SWT.Selection, e -> selectFilePipeline());
+ Button wbOpen = new Button(shell, SWT.PUSH);
+ ReferencedFileOpener.configureOpenButton(wbOpen);
+ FormData fdOpen = new FormData();
+ fdOpen.right = new FormAttachment(wbBrowse, -margin);
+ fdOpen.top = new FormAttachment(wlPath, 0, SWT.CENTER);
+ wbOpen.setLayoutData(fdOpen);
+ wbOpen.addListener(SWT.Selection, e -> openReferencedFile());
+
wPath = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
PropsUi.setLook(wPath);
+ wPath.addModifyListener(lsMod);
FormData fdTransformation = new FormData();
fdTransformation.left = new FormAttachment(wlPath, margin);
fdTransformation.top = new FormAttachment(wlPath, 0, SWT.CENTER);
- fdTransformation.right = new FormAttachment(wbBrowse, -margin);
+ fdTransformation.right = new FormAttachment(wbOpen, -margin);
wPath.setLayoutData(fdTransformation);
// The run configuration
@@ -241,6 +251,19 @@ public class SimpleMappingDialog extends
BaseTransformDialog {
return transformName;
}
+ private void openReferencedFile() {
+ ReferencedFileOpener.openFromDialog(
+ shell,
+ variables,
+ wPath.getText(),
+ ReferencedFileOpener.isDialogModified(
+ mappingMeta.hasChanged(), wPath.getText(),
mappingMeta.getFilename()),
+ () -> {
+ ok();
+ return isDisposed() ? mappingMeta.getFilename() : null;
+ });
+ }
+
private void selectFilePipeline() {
try {
diff --git
a/plugins/transforms/mapping/src/main/java/org/apache/hop/pipeline/transforms/multimapping/MultiMappingDialog.java
b/plugins/transforms/mapping/src/main/java/org/apache/hop/pipeline/transforms/multimapping/MultiMappingDialog.java
index d2324aad4c..77829cd161 100644
---
a/plugins/transforms/mapping/src/main/java/org/apache/hop/pipeline/transforms/multimapping/MultiMappingDialog.java
+++
b/plugins/transforms/mapping/src/main/java/org/apache/hop/pipeline/transforms/multimapping/MultiMappingDialog.java
@@ -52,7 +52,7 @@ import org.apache.hop.ui.core.widget.ColumnsResizer;
import org.apache.hop.ui.core.widget.ComboVar;
import org.apache.hop.ui.core.widget.TableView;
import org.apache.hop.ui.core.widget.TextVar;
-import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.ReferencedFileOpener;
import org.apache.hop.ui.hopgui.file.pipeline.HopPipelineFileType;
import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
import org.eclipse.swt.SWT;
@@ -281,18 +281,16 @@ public class MultiMappingDialog extends
BaseTransformDialog {
}
private void editPipeline() {
- try {
- if (Utils.isEmpty(wPath.getText())) {
- return;
- }
-
HopGui.getInstance().fileDelegate.fileOpen(variables.resolve(wPath.getText()));
- } catch (Exception ex) {
- new ErrorDialog(
- shell,
- BaseMessages.getString(PKG,
"MultiMappingDialog.ErrorLoadingPipeline.DialogTitle"),
- BaseMessages.getString(PKG,
"MultiMappingDialog.ErrorLoadingPipeline.DialogMessage"),
- ex);
- }
+ ReferencedFileOpener.openFromDialog(
+ shell,
+ variables,
+ wPath.getText(),
+ ReferencedFileOpener.isDialogModified(
+ mappingMeta.hasChanged(), wPath.getText(),
mappingMeta.getFilename()),
+ () -> {
+ ok();
+ return isDisposed() ? mappingMeta.getFilename() : null;
+ });
}
private void loadPipelineFile(String fname) throws HopException {
diff --git
a/plugins/transforms/metainject/src/main/java/org/apache/hop/pipeline/transforms/metainject/MetaInjectDialog.java
b/plugins/transforms/metainject/src/main/java/org/apache/hop/pipeline/transforms/metainject/MetaInjectDialog.java
index 991ae51e14..6db0eda5f1 100644
---
a/plugins/transforms/metainject/src/main/java/org/apache/hop/pipeline/transforms/metainject/MetaInjectDialog.java
+++
b/plugins/transforms/metainject/src/main/java/org/apache/hop/pipeline/transforms/metainject/MetaInjectDialog.java
@@ -59,6 +59,7 @@ import org.apache.hop.ui.core.widget.ComboVar;
import org.apache.hop.ui.core.widget.TableView;
import org.apache.hop.ui.core.widget.TextVar;
import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.ReferencedFileOpener;
import org.apache.hop.ui.hopgui.file.pipeline.HopPipelineFileType;
import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
import org.eclipse.swt.SWT;
@@ -201,12 +202,21 @@ public class MetaInjectDialog extends BaseTransformDialog
{
fdBrowse.top = new FormAttachment(wlPath, Const.isOSX() ? 0 : 5);
wbBrowse.setLayoutData(fdBrowse);
+ Button wbOpen = new Button(shell, SWT.PUSH);
+ ReferencedFileOpener.configureOpenButton(wbOpen);
+ FormData fdOpen = new FormData();
+ fdOpen.right = new FormAttachment(wbBrowse, -PropsUi.getMargin());
+ fdOpen.top = new FormAttachment(wlPath, Const.isOSX() ? 0 : 5);
+ wbOpen.setLayoutData(fdOpen);
+ wbOpen.addListener(SWT.Selection, e -> openReferencedFile());
+
wPath = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
PropsUi.setLook(wPath);
+ wPath.addModifyListener(lsMod);
FormData fdTransformation = new FormData();
fdTransformation.left = new FormAttachment(0, 0);
fdTransformation.top = new FormAttachment(wlPath, 5);
- fdTransformation.right = new FormAttachment(wbBrowse,
-PropsUi.getMargin());
+ fdTransformation.right = new FormAttachment(wbOpen, -PropsUi.getMargin());
wPath.setLayoutData(fdTransformation);
wPath.addFocusListener(
new FocusAdapter() {
@@ -859,6 +869,19 @@ public class MetaInjectDialog extends BaseTransformDialog {
}
}
+ private void openReferencedFile() {
+ ReferencedFileOpener.openFromDialog(
+ shell,
+ variables,
+ wPath.getText(),
+ ReferencedFileOpener.isDialogModified(
+ metaInjectMeta.hasChanged(), wPath.getText(),
metaInjectMeta.getTemplateFileName()),
+ () -> {
+ ok();
+ return isDisposed() ? metaInjectMeta.getTemplateFileName() : null;
+ });
+ }
+
private void selectFileTrans() {
try {
HopPipelineFileType<PipelineMeta> fileType =
diff --git
a/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorDialog.java
b/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorDialog.java
index 0b1b2fbf5e..45ec3481b7 100644
---
a/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorDialog.java
+++
b/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorDialog.java
@@ -48,6 +48,7 @@ import org.apache.hop.ui.core.widget.MetaSelectionLine;
import org.apache.hop.ui.core.widget.TableView;
import org.apache.hop.ui.core.widget.TextVar;
import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.ReferencedFileOpener;
import org.apache.hop.ui.hopgui.file.pipeline.HopPipelineFileType;
import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
import org.eclipse.swt.SWT;
@@ -88,6 +89,7 @@ public class PipelineExecutorDialog extends
BaseTransformDialog {
private Label wlPath;
private TextVar wPath;
+ private Button wbOpen;
protected MetaSelectionLine<PipelineRunConfiguration> wRunConfiguration;
@@ -180,12 +182,21 @@ public class PipelineExecutorDialog extends
BaseTransformDialog {
wbBrowse.setLayoutData(fdBrowse);
wbBrowse.addListener(SWT.Selection, e -> selectPipelineFile());
+ wbOpen = new Button(shell, SWT.PUSH);
+ ReferencedFileOpener.configureOpenButton(wbOpen);
+ FormData fdOpen = new FormData();
+ fdOpen.right = new FormAttachment(wbBrowse, -margin);
+ fdOpen.top = new FormAttachment(wlPath, 0, SWT.CENTER);
+ wbOpen.setLayoutData(fdOpen);
+ wbOpen.addListener(SWT.Selection, e -> openReferencedFile());
+
wPath = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
PropsUi.setLook(wPath);
+ wPath.addModifyListener(lsMod);
FormData fdTransformation = new FormData();
fdTransformation.left = new FormAttachment(middle, 0);
fdTransformation.top = new FormAttachment(wlPath, 0, SWT.CENTER);
- fdTransformation.right = new FormAttachment(wbBrowse, -margin);
+ fdTransformation.right = new FormAttachment(wbOpen, -margin);
wPath.setLayoutData(fdTransformation);
wbPipelineNameInField = new Button(shell, SWT.CHECK);
@@ -721,11 +732,25 @@ public class PipelineExecutorDialog extends
BaseTransformDialog {
}
}
+ private void openReferencedFile() {
+ ReferencedFileOpener.openFromDialog(
+ shell,
+ variables,
+ wPath.getText(),
+ ReferencedFileOpener.isDialogModified(
+ pipelineExecutorMeta.hasChanged(), wPath.getText(),
pipelineExecutorMeta.getFilename()),
+ () -> {
+ ok();
+ return isDisposed() ? pipelineExecutorMeta.getFilename() : null;
+ });
+ }
+
private void activePipelineNameField() {
wlPipelineNameField.setEnabled(wbPipelineNameInField.getSelection());
wPipelineNameField.setEnabled(wbPipelineNameInField.getSelection());
wPath.setEnabled(!wbPipelineNameInField.getSelection());
wlPath.setEnabled(!wbPipelineNameInField.getSelection());
+ wbOpen.setEnabled(!wbPipelineNameInField.getSelection());
if (wbPipelineNameInField.getSelection()) {
wPath.setText("");
} else {
diff --git
a/plugins/transforms/workflowexecutor/src/main/java/org/apache/hop/pipeline/transforms/workflowexecutor/WorkflowExecutorDialog.java
b/plugins/transforms/workflowexecutor/src/main/java/org/apache/hop/pipeline/transforms/workflowexecutor/WorkflowExecutorDialog.java
index 7051086578..c868989d71 100644
---
a/plugins/transforms/workflowexecutor/src/main/java/org/apache/hop/pipeline/transforms/workflowexecutor/WorkflowExecutorDialog.java
+++
b/plugins/transforms/workflowexecutor/src/main/java/org/apache/hop/pipeline/transforms/workflowexecutor/WorkflowExecutorDialog.java
@@ -46,6 +46,7 @@ import org.apache.hop.ui.core.widget.MetaSelectionLine;
import org.apache.hop.ui.core.widget.TableView;
import org.apache.hop.ui.core.widget.TextVar;
import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.file.ReferencedFileOpener;
import org.apache.hop.ui.hopgui.file.workflow.HopWorkflowFileType;
import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
import org.apache.hop.workflow.WorkflowMeta;
@@ -87,6 +88,7 @@ public class WorkflowExecutorDialog extends
BaseTransformDialog {
private Label wlPath;
private TextVar wPath;
private Button wbBrowse;
+ private Button wbOpen;
private Button wbWorkflowNameInField;
@@ -182,12 +184,21 @@ public class WorkflowExecutorDialog extends
BaseTransformDialog {
wbBrowse.setLayoutData(fdBrowse);
wbBrowse.addListener(SWT.Selection, e -> selectWorkflowFile());
+ wbOpen = new Button(shell, SWT.PUSH);
+ ReferencedFileOpener.configureOpenButton(wbOpen);
+ FormData fdOpen = new FormData();
+ fdOpen.right = new FormAttachment(wbBrowse, -margin);
+ fdOpen.bottom = new FormAttachment(wlPath, 0, SWT.CENTER);
+ wbOpen.setLayoutData(fdOpen);
+ wbOpen.addListener(SWT.Selection, e -> openReferencedFile());
+
wPath = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
PropsUi.setLook(wPath);
+ wPath.addModifyListener(lsMod);
FormData fdPath = new FormData();
fdPath.left = new FormAttachment(wlPath, margin);
fdPath.top = new FormAttachment(wlPath, 0, SWT.CENTER);
- fdPath.right = new FormAttachment(wbBrowse, -margin);
+ fdPath.right = new FormAttachment(wbOpen, -margin);
wPath.setLayoutData(fdPath);
wbWorkflowNameInField = new Button(shell, SWT.CHECK);
@@ -332,12 +343,26 @@ public class WorkflowExecutorDialog extends
BaseTransformDialog {
}
}
+ private void openReferencedFile() {
+ ReferencedFileOpener.openFromDialog(
+ shell,
+ variables,
+ wPath.getText(),
+ ReferencedFileOpener.isDialogModified(
+ workflowExecutorMeta.hasChanged(), wPath.getText(),
workflowExecutorMeta.getFilename()),
+ () -> {
+ ok();
+ return isDisposed() ? workflowExecutorMeta.getFilename() : null;
+ });
+ }
+
private void activeWorkflowNameField() {
wlWorkflowNameField.setEnabled(wbWorkflowNameInField.getSelection());
wWorkflowNameField.setEnabled(wbWorkflowNameInField.getSelection());
wPath.setEnabled(!wbWorkflowNameInField.getSelection());
wlPath.setEnabled(!wbWorkflowNameInField.getSelection());
wbBrowse.setEnabled(!wbWorkflowNameInField.getSelection());
+ wbOpen.setEnabled(!wbWorkflowNameInField.getSelection());
if (wbWorkflowNameInField.getSelection()) {
wPath.setText("");
} else {
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/ReferencedFileOpener.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/ReferencedFileOpener.java
new file mode 100644
index 0000000000..c174ac82b7
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/file/ReferencedFileOpener.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.hopgui.file;
+
+import java.util.function.Supplier;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hop.core.security.HopDialogEditGuard;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.i18n.BaseMessages;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.core.dialog.BaseDialog;
+import org.apache.hop.ui.core.dialog.ErrorDialog;
+import org.apache.hop.ui.core.dialog.MessageBox;
+import org.apache.hop.ui.hopgui.HopGui;
+import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Opens the pipeline or workflow selected in a transform or action dialog.
+ *
+ * <p>When the dialog has unsaved edits, the user is asked to save them first.
Saving applies the
+ * dialog (the same as OK) and then opens the file. Declining opens the file
and leaves the dialog
+ * open. Cancelling does nothing.
+ */
+public final class ReferencedFileOpener {
+ private static final Class<?> PKG = ReferencedFileOpener.class;
+
+ private ReferencedFileOpener() {}
+
+ /** What to do after the optional save question. */
+ public enum Decision {
+ APPLY_AND_OPEN,
+ OPEN,
+ CANCEL
+ }
+
+ /**
+ * @param modified whether the dialog has edits that OK would keep
+ * @param answer a {@link SWT} yes/no/cancel code; ignored when {@code
modified} is false
+ */
+ public static Decision decide(boolean modified, int answer) {
+ if (!modified) {
+ return Decision.OPEN;
+ }
+ if (answer == SWT.YES) {
+ return Decision.APPLY_AND_OPEN;
+ }
+ if (answer == SWT.NO) {
+ return Decision.OPEN;
+ }
+ return Decision.CANCEL;
+ }
+
+ /** True when {@code filename} resolves to a non-blank path. */
+ public static boolean hasOpenableFilename(IVariables variables, String
filename) {
+ if (variables == null || StringUtils.isBlank(filename)) {
+ return false;
+ }
+ return StringUtils.isNotBlank(variables.resolve(filename));
+ }
+
+ /**
+ * True when the dialog metadata is already marked changed, or the filename
field differs from the
+ * value stored on the transform or action.
+ */
+ public static boolean isDialogModified(
+ boolean changed, String currentFilename, String storedFilename) {
+ if (changed) {
+ return true;
+ }
+ return !StringUtils.equals(
+ StringUtils.defaultString(currentFilename),
StringUtils.defaultString(storedFilename));
+ }
+
+ /** Label, tooltip and read-only behaviour shared by the Open buttons. */
+ public static void configureOpenButton(Button button) {
+ PropsUi.setLook(button);
+ button.setText(BaseMessages.getString(PKG, "System.Button.Open"));
+ button.setToolTipText(BaseMessages.getString(PKG,
"ReferencedFileOpener.Open.Tooltip"));
+ BaseDialog.keepEnabledInReadOnly(button);
+ }
+
+ /**
+ * Open {@code filename} from a dialog.
+ *
+ * @param apply saves the dialog and returns the filename to open, or {@code
null} when saving did
+ * not complete
+ */
+ public static void openFromDialog(
+ Shell shell,
+ IVariables variables,
+ String filename,
+ boolean modified,
+ Supplier<String> apply) {
+ if (!hasOpenableFilename(variables, filename)) {
+ MessageBox box = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
+ box.setText(BaseMessages.getString(PKG,
"ReferencedFileOpener.FilenameMissing.Title"));
+ box.setMessage(BaseMessages.getString(PKG,
"ReferencedFileOpener.FilenameMissing.Message"));
+ box.open();
+ return;
+ }
+ if (isReadOnly(shell)) {
+ modified = false;
+ }
+ Decision decision = decide(modified, modified ? askToSave(shell) :
SWT.NONE);
+ if (decision == Decision.CANCEL) {
+ return;
+ }
+ String toOpen = filename;
+ if (decision == Decision.APPLY_AND_OPEN) {
+ toOpen = apply == null ? null : apply.get();
+ if (!hasOpenableFilename(variables, toOpen)) {
+ return;
+ }
+ }
+ openResolved(variables.resolve(toOpen), shell);
+ }
+
+ private static boolean isReadOnly(Shell shell) {
+ if (shell == null || shell.isDisposed()) {
+ return false;
+ }
+ return
HopDialogEditGuard.isReadOnly(shell.getData(BaseDialog.DIALOG_SUBJECT));
+ }
+
+ private static int askToSave(Shell shell) {
+ MessageBox box = new MessageBox(shell, SWT.YES | SWT.NO | SWT.CANCEL |
SWT.ICON_QUESTION);
+ box.setText(BaseMessages.getString(PKG,
"ReferencedFileOpener.SaveChanges.Title"));
+ box.setMessage(BaseMessages.getString(PKG,
"ReferencedFileOpener.SaveChanges.Message"));
+ return box.open();
+ }
+
+ private static void openResolved(String filename, Shell dialogShell) {
+ try {
+ HopGui hopGui = HopGui.getInstance();
+ ExplorerPerspective perspective = HopGui.getExplorerPerspective();
+ if (perspective != null) {
+ IHopFileTypeHandler existing =
perspective.findFileTypeHandlerByFilename(filename);
+ if (existing != null) {
+ perspective.setActiveFileTypeHandler(existing);
+ perspective.activate();
+ return;
+ }
+ }
+ hopGui.fileDelegate.fileOpen(filename);
+ } catch (Exception e) {
+ Shell parent = parentShell(dialogShell);
+ if (parent == null) {
+ return;
+ }
+ new ErrorDialog(
+ parent,
+ BaseMessages.getString(PKG,
"ReferencedFileOpener.ErrorOpening.Title"),
+ BaseMessages.getString(PKG,
"ReferencedFileOpener.ErrorOpening.Message", filename),
+ e);
+ }
+ }
+
+ private static Shell parentShell(Shell dialogShell) {
+ if (dialogShell != null && !dialogShell.isDisposed()) {
+ return dialogShell;
+ }
+ HopGui hopGui = HopGui.getInstance();
+ if (hopGui == null || hopGui.getShell() == null ||
hopGui.getShell().isDisposed()) {
+ return null;
+ }
+ return hopGui.getShell();
+ }
+}
diff --git
a/ui/src/main/java/org/apache/hop/ui/workflow/actions/ActionBaseDialog.java
b/ui/src/main/java/org/apache/hop/ui/workflow/actions/ActionBaseDialog.java
index 48d7fe4562..adc4d03669 100644
--- a/ui/src/main/java/org/apache/hop/ui/workflow/actions/ActionBaseDialog.java
+++ b/ui/src/main/java/org/apache/hop/ui/workflow/actions/ActionBaseDialog.java
@@ -37,6 +37,7 @@ import org.apache.hop.ui.core.widget.NamingSchemeTypes;
import org.apache.hop.ui.core.widget.NamingSchemeWidgetSupport;
import org.apache.hop.ui.core.widget.TableView;
import org.apache.hop.ui.core.widget.TextVar;
+import org.apache.hop.ui.hopgui.file.ReferencedFileOpener;
import org.apache.hop.ui.pipeline.transform.BaseTransformDialog;
import org.apache.hop.ui.workflow.action.ActionDialog;
import org.apache.hop.workflow.WorkflowMeta;
@@ -70,6 +71,7 @@ public abstract class ActionBaseDialog extends ActionDialog {
protected TextVar wPath;
protected Button wbBrowse;
+ protected Button wbOpen;
protected Group gLogFile;
@@ -241,12 +243,21 @@ public abstract class ActionBaseDialog extends
ActionDialog {
fdBrowse.top = new FormAttachment(wlPath, Const.isOSX() ? 0 : 5);
wbBrowse.setLayoutData(fdBrowse);
+ wbOpen = new Button(shell, SWT.PUSH);
+ ReferencedFileOpener.configureOpenButton(wbOpen);
+ FormData fdOpen = new FormData();
+ fdOpen.right = new FormAttachment(wbBrowse, -5);
+ fdOpen.top = new FormAttachment(wlPath, Const.isOSX() ? 0 : 5);
+ wbOpen.setLayoutData(fdOpen);
+ wbOpen.addListener(SWT.Selection, e -> openReferencedFile());
+
wPath = new TextVar(variables, shell, SWT.SINGLE | SWT.LEFT | SWT.BORDER);
PropsUi.setLook(wPath);
+ wPath.addModifyListener(lsMod);
FormData fdPath = new FormData();
fdPath.left = new FormAttachment(0, 0);
fdPath.top = new FormAttachment(wlPath, 5);
- fdPath.right = new FormAttachment(wbBrowse, -5);
+ fdPath.right = new FormAttachment(wbOpen, -5);
wPath.setLayoutData(fdPath);
Label wlRunConfiguration = new Label(shell, SWT.LEFT);
@@ -640,6 +651,19 @@ public abstract class ActionBaseDialog extends
ActionDialog {
}
}
+ private void openReferencedFile() {
+ ReferencedFileOpener.openFromDialog(
+ shell,
+ variables,
+ wPath.getText(),
+ ReferencedFileOpener.isDialogModified(
+ getAction().hasChanged(), wPath.getText(),
getAction().getFilename()),
+ () -> {
+ ok();
+ return isDisposed() ? getAction().getFilename() : null;
+ });
+ }
+
protected abstract void ok();
protected abstract void cancel();
diff --git
a/ui/src/main/resources/org/apache/hop/ui/hopgui/file/messages/messages_en_US.properties
b/ui/src/main/resources/org/apache/hop/ui/hopgui/file/messages/messages_en_US.properties
index 7c7fbe2d57..30227c4708 100644
---
a/ui/src/main/resources/org/apache/hop/ui/hopgui/file/messages/messages_en_US.properties
+++
b/ui/src/main/resources/org/apache/hop/ui/hopgui/file/messages/messages_en_US.properties
@@ -17,3 +17,10 @@
#
HopFileTypeRegistry.FileTypes.All.Label=All Hop file types
+ReferencedFileOpener.Open.Tooltip=Open the pipeline or workflow
+ReferencedFileOpener.SaveChanges.Title=Save changes?
+ReferencedFileOpener.SaveChanges.Message=This dialog has been modified. Do you
want to save your changes before opening the file?
+ReferencedFileOpener.FilenameMissing.Title=Filename is missing
+ReferencedFileOpener.FilenameMissing.Message=Please enter a filename before
opening the file.
+ReferencedFileOpener.ErrorOpening.Title=Error opening file
+ReferencedFileOpener.ErrorOpening.Message=Error opening file ''{0}''
diff --git
a/ui/src/test/java/org/apache/hop/ui/hopgui/file/ReferencedFileOpenerTest.java
b/ui/src/test/java/org/apache/hop/ui/hopgui/file/ReferencedFileOpenerTest.java
new file mode 100644
index 0000000000..5f617c61c5
--- /dev/null
+++
b/ui/src/test/java/org/apache/hop/ui/hopgui/file/ReferencedFileOpenerTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.hopgui.file;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.core.variables.Variables;
+import org.eclipse.swt.SWT;
+import org.junit.jupiter.api.Test;
+
+class ReferencedFileOpenerTest {
+
+ @Test
+ void unchangedDialogOpensWithoutApplying() {
+ assertEquals(ReferencedFileOpener.Decision.OPEN,
ReferencedFileOpener.decide(false, SWT.YES));
+ assertEquals(
+ ReferencedFileOpener.Decision.OPEN, ReferencedFileOpener.decide(false,
SWT.CANCEL));
+ }
+
+ @Test
+ void modifiedDialogFollowsTheSaveAnswer() {
+ assertEquals(
+ ReferencedFileOpener.Decision.APPLY_AND_OPEN,
ReferencedFileOpener.decide(true, SWT.YES));
+ assertEquals(ReferencedFileOpener.Decision.OPEN,
ReferencedFileOpener.decide(true, SWT.NO));
+ assertEquals(
+ ReferencedFileOpener.Decision.CANCEL,
ReferencedFileOpener.decide(true, SWT.CANCEL));
+ assertEquals(ReferencedFileOpener.Decision.CANCEL,
ReferencedFileOpener.decide(true, SWT.NONE));
+ }
+
+ @Test
+ void filenameFieldOrChangedFlagMarksTheDialogModified() {
+ assertFalse(ReferencedFileOpener.isDialogModified(false, "pipe.hpl",
"pipe.hpl"));
+ assertFalse(ReferencedFileOpener.isDialogModified(false, null, null));
+ assertFalse(ReferencedFileOpener.isDialogModified(false, "", null));
+ assertTrue(ReferencedFileOpener.isDialogModified(false, "other.hpl",
"pipe.hpl"));
+ assertTrue(ReferencedFileOpener.isDialogModified(true, "pipe.hpl",
"pipe.hpl"));
+ }
+
+ @Test
+ void blankOrUnresolvedEmptyFilenameIsNotOpened() {
+ IVariables variables = new Variables();
+ variables.setVariable("FOLDER", "/data");
+ variables.setVariable("EMPTY", "");
+
+ assertFalse(ReferencedFileOpener.hasOpenableFilename(null, "pipe.hpl"));
+ assertFalse(ReferencedFileOpener.hasOpenableFilename(variables, null));
+ assertFalse(ReferencedFileOpener.hasOpenableFilename(variables, " "));
+ assertFalse(ReferencedFileOpener.hasOpenableFilename(variables,
"${EMPTY}"));
+ assertTrue(ReferencedFileOpener.hasOpenableFilename(variables,
"${FOLDER}/pipe.hpl"));
+ }
+}