Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.eclipse.nebula.widgets.nattable.util.PlatformHelper;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.slf4j.Logger;
Expand Down Expand Up @@ -107,6 +108,16 @@ public class NatExporter {
*/
private boolean useProgressDialog = false;

/**
* The {@link Runnable} that should be executed after the export finished
* successfully. Useful in case {@link #openResult} is set to
* <code>false</code> so an alternative for reporting the export success can
* be configured.
*
* @since 2.6
*/
private Runnable successRunnable;

/**
* Create a new {@link NatExporter}.
*
Expand Down Expand Up @@ -160,13 +171,56 @@ public NatExporter(Shell shell, boolean executeSynchronously) {
* is made based on whether a {@link Shell} is set or not. If a
* {@link Shell} is set and this flag is set to <code>true</code>
* the execution is performed synchronously.
* @param useProgressDialog
* Configure whether the progress should be reported via
* {@link ProgressMonitorDialog}. If set to <code>false</code> a
* custom shell with a {@link ProgressBar} will be shown if the
* shell parameter is not <code>null</code>.
*
* @since 2.3
*/
public NatExporter(Shell shell, boolean executeSynchronously, boolean useProgressDialog) {
this(shell, executeSynchronously, useProgressDialog, true, null);
}

/**
* Create a new {@link NatExporter}.
*
* @param shell
* The {@link Shell} that should be used to open sub-dialogs and
* perform export operations in a background thread. Can be
* <code>null</code> but could lead to
* {@link NullPointerException}s if {@link IExporter} are
* configured, that use a {@link FileOutputStreamProvider}.
* @param executeSynchronously
* Configure whether the export should be performed
* asynchronously or synchronously. By default the decision
* whether the execution should be performed synchronously or not
* is made based on whether a {@link Shell} is set or not. If a
* {@link Shell} is set and this flag is set to <code>true</code>
* the execution is performed synchronously.
* @param useProgressDialog
* Configure whether the progress should be reported via
* {@link ProgressMonitorDialog}. If set to <code>false</code> a
* custom shell with a {@link ProgressBar} will be shown if the
* shell parameter is not <code>null</code>.
* @param openResult
* Configure if the created export result should be opened after
* the export is finished.
* @param successRunnable
* The {@link Runnable} that should be executed after the export
* finished successfully. Useful in case {@link #openResult} is
* set to <code>false</code> so an alternative for reporting the
* export success can be configured.
*
* @since 2.6
*/
public NatExporter(Shell shell, boolean executeSynchronously, boolean useProgressDialog, boolean openResult, Runnable successRunnable) {
this.shell = shell;
this.runAsynchronously = !executeSynchronously;
this.useProgressDialog = useProgressDialog;
this.openResult = openResult;
this.successRunnable = successRunnable;
}

/**
Expand Down Expand Up @@ -946,17 +1000,29 @@ protected void setClientAreaToMaximum(ILayer layer) {
* @since 1.5
*/
protected void openExport(IExporter exporter) {
if (this.exportSucceeded
&& this.openResult
&& exporter.getResult() != null
&& exporter.getResult() instanceof File) {
if (this.exportSucceeded) {

try {
Class<?> program = Class.forName("org.eclipse.swt.program.Program"); //$NON-NLS-1$
Method launch = program.getMethod("launch", String.class); //$NON-NLS-1$
launch.invoke(null, ((File) exporter.getResult()).getAbsolutePath());
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
LOG.info("Could not open the export because org.eclipse.swt.program.Program, you are probably running a RAP application."); //$NON-NLS-1$
if (this.successRunnable != null) {
if (this.shell != null) {
this.shell.getDisplay().syncExec(() -> {
this.successRunnable.run();
});
} else {
this.successRunnable.run();
}
}

if (this.openResult
&& exporter.getResult() != null
&& exporter.getResult() instanceof File) {

try {
Class<?> program = Class.forName("org.eclipse.swt.program.Program"); //$NON-NLS-1$
Method launch = program.getMethod("launch", String.class); //$NON-NLS-1$
launch.invoke(null, ((File) exporter.getResult()).getAbsolutePath());
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
LOG.info("Could not open the export because org.eclipse.swt.program.Program, you are probably running a RAP application."); //$NON-NLS-1$
}
}
}
}
Expand Down Expand Up @@ -1061,4 +1127,20 @@ public boolean isUseProgressDialog() {
public void setUseProgressDialog(boolean useProgressDialog) {
this.useProgressDialog = useProgressDialog;
}

/**
* Configure a {@link Runnable} that should be executed after a successful
* export operation. If a {@link #shell} is set, the {@link Runnable} is
* executed using {@link Display#syncExec(Runnable)}.
*
* @param successRunnable
* The {@link Runnable} that should be executed after the export
* finished successfully. Useful in case {@link #openResult} is
* set to <code>false</code> so an alternative for reporting the
* export success can be configured.
* @since 2.6
*/
public void setSuccessRunnable(Runnable successRunnable) {
this.successRunnable = successRunnable;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012, 2023 Original authors and others.
* Copyright (c) 2012, 2025 Original authors and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -31,6 +31,8 @@ public class ExportCommand extends AbstractContextFreeCommand {
private final boolean executeSynchronously;
private final boolean useProgressDialog;
private final ILayerExporter exporter;
private final boolean openResult;
private final Runnable successRunnable;

/**
* Creates a new {@link ExportCommand}.
Expand Down Expand Up @@ -124,11 +126,59 @@ public ExportCommand(IConfigRegistry configRegistry, Shell shell, boolean execut
* @since 2.3
*/
public ExportCommand(IConfigRegistry configRegistry, Shell shell, boolean executeSynchronously, boolean useProgressDialog, ILayerExporter exporter) {
this(configRegistry, shell, executeSynchronously, useProgressDialog, exporter, true, null);
}

/**
* Creates a new {@link ExportCommand}.
*
* @param configRegistry
* The {@link IConfigRegistry} that contains the necessary export
* configurations.
* @param shell
* The {@link Shell} that should be used to open sub-dialogs and
* perform export operations in a background thread. Can be
* <code>null</code> which definitely leads to synchronous
* execution but could cause errors in case sub-dialogs should be
* opened before exporting.
* @param executeSynchronously
* Configure if the export should be performed synchronously even
* if a {@link Shell} is set.
* @param useProgressDialog
* Configure whether the progress should be reported via
* {@link ProgressMonitorDialog}. If set to <code>false</code> a
* custom shell with a {@link ProgressBar} will be shown if the
* shell parameter is not <code>null</code>.
* @param exporter
* The {@link ILayerExporter} that should be used. Can be
* <code>null</code>, which causes the usage of the exporter
* registered in the {@link IConfigRegistry}.
* @param openResult
* Configure if the created export result should be opened after
* the export is finished.
* @param successRunnable
* The {@link Runnable} that should be executed after the export
* finished successfully. Useful in case {@link #openResult} is
* set to <code>false</code> so an alternative for reporting the
* export success can be configured.
* @since 2.6
*/
public ExportCommand(
IConfigRegistry configRegistry,
Shell shell,
boolean executeSynchronously,
boolean useProgressDialog,
ILayerExporter exporter,
boolean openResult,
Runnable successRunnable) {

this.configRegistry = configRegistry;
this.shell = shell;
this.executeSynchronously = executeSynchronously;
this.useProgressDialog = useProgressDialog;
this.exporter = exporter;
this.openResult = openResult;
this.successRunnable = successRunnable;
}

/**
Expand Down Expand Up @@ -185,4 +235,26 @@ public boolean isUseProgressDialog() {
public ILayerExporter getExporter() {
return this.exporter;
}

/**
*
* @return <code>true</code> if the created export file should be opened
* after the export finished successfully, <code>false</code> if not
* @since 2.6
*/
public boolean isOpenResult() {
return this.openResult;
}

/**
*
* @return The {@link Runnable} that should be executed after the export
* finished successfully. Useful in case {@link #openResult} is set
* to <code>false</code> so an alternative for reporting the export
* success can be configured.
* @since 2.6
*/
public Runnable getSuccessRunnable() {
return this.successRunnable;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012, 2023 Original authors and others.
* Copyright (c) 2012, 2025 Original authors and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -37,18 +37,17 @@ public ExportCommandHandler(ILayer layer) {

@Override
public boolean doCommand(final ExportCommand command) {
NatExporter natExporter = new NatExporter(
command.getShell(),
command.isExecuteSynchronously(),
command.isUseProgressDialog(),
command.isOpenResult(),
command.getSuccessRunnable());

if (command.getExporter() == null) {
new NatExporter(
command.getShell(),
command.isExecuteSynchronously(),
command.isUseProgressDialog())
.exportSingleLayer(this.layer, command.getConfigRegistry());
natExporter.exportSingleLayer(this.layer, command.getConfigRegistry());
} else {
new NatExporter(
command.getShell(),
command.isExecuteSynchronously(),
command.isUseProgressDialog())
.exportSingleLayer(command.getExporter(), this.layer, command.getConfigRegistry());
natExporter.exportSingleLayer(command.getExporter(), this.layer, command.getConfigRegistry());
}

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.List;
import java.util.Map;

import org.eclipse.nebula.widgets.nattable.command.DisposeResourcesCommand;
import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry;
import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
import org.eclipse.nebula.widgets.nattable.data.IColumnPropertyAccessor;
Expand Down Expand Up @@ -60,6 +61,7 @@
import org.eclipse.nebula.widgets.nattable.sort.config.DefaultSortConfiguration;
import org.eclipse.nebula.widgets.nattable.tree.TreeLayer;
import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -176,6 +178,11 @@ public void setup() {
this.natTable.configure();
}

@AfterEach
public void tearDown() {
this.natTable.doCommand(new DisposeResourcesCommand());
}

@Test
public void shouldUpdateGroupByModelViaGroupByCommand() {
this.natTable.doCommand(new GroupByCommand(GroupByAction.ADD, 1));
Expand Down