Skip to content
Snippets Groups Projects
Commit d04d8944 authored by Petr Bainar's avatar Petr Bainar
Browse files

Merge branch 'macFix' into 'master'

Fixing freezes on MacOS

See merge request fiji/haas-java-client!16
parents b91b20e3 14d97690
No related branches found
No related tags found
1 merge request!16Fixing freezes on MacOS
package cz.it4i.fiji.haas.ui;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
......@@ -62,10 +66,21 @@ public interface JavaFXRoutines {
}
static public void runOnFxThread(Runnable runnable) {
RunnableFuture<Void> task = new FutureTask<>(runnable, null);
if (Platform.isFxApplicationThread()) {
runnable.run();
} else {
Platform.runLater(runnable);
task.run();
}
else {
Platform.runLater(task);
}
try {
task.get();
}
catch (InterruptedException | ExecutionException e) {
log.error(e.getMessage(), e);
}
}
......
package cz.it4i.fiji.haas.ui;
import java.awt.Desktop;
import java.io.IOException;
import java.nio.file.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public interface ShellRoutines {
public static final Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas.ui.ShellRoutines.class);
public static void openDirectoryInBrowser(Path directory) {
public static void openDirectoryInBrowser(Path directory)
throws UnsupportedOperationException, IOException
{
if (!Desktop.isDesktopSupported()) {
throw new UnsupportedOperationException(
"Desktop.getDesktop() is not supported on the current platform.");
}
Desktop desktop = Desktop.getDesktop();
try {
desktop.open(directory.toFile());
} catch (IOException e) {
log.error(e.getMessage(), e);
if (!desktop.isSupported(Desktop.Action.OPEN)) {
throw new UnsupportedOperationException(
"Desktop.open() is not supported on the current platform.");
}
desktop.open(directory.toFile());
}
}
package cz.it4i.fiji.haas_spim_benchmark.commands;
import java.awt.event.WindowAdapter;
......@@ -27,37 +28,36 @@ import cz.it4i.fiji.haas_spim_benchmark.core.Constants;
import cz.it4i.fiji.haas_spim_benchmark.ui.BenchmarkSPIMWindow;
/**
*
* @author koz01
*
*/
@Plugin(type = Command.class, headless = false, menuPath = "Plugins>" + Constants.MENU_ITEM_NAME + ">" + Constants.SUBMENU_ITEM_NAME)
@Plugin(type = Command.class, headless = false, menuPath = "Plugins>" +
Constants.MENU_ITEM_NAME + ">" + Constants.SUBMENU_ITEM_NAME)
public class ManageSPIMBenchmark implements Command {
private static Logger log = LoggerFactory
.getLogger(cz.it4i.fiji.haas_spim_benchmark.commands.ManageSPIMBenchmark.class);
private static Logger log = LoggerFactory.getLogger(
cz.it4i.fiji.haas_spim_benchmark.commands.ManageSPIMBenchmark.class);
private static final String LOCK_FILE_NAME = ".lock";
@Parameter
private UIService uiService;
@Parameter
private Context context;
@Parameter(style = TextWidget.FIELD_STYLE, label = "User name")
private String userName;
@Parameter(style = TextWidget.PASSWORD_STYLE)
private String password;
@Parameter(style = TextWidget.FIELD_STYLE)
private String email;
@Parameter(label = "Working directory", persist = true, style = FileWidget.DIRECTORY_STYLE)
@Parameter(label = "Working directory", persist = true,
style = FileWidget.DIRECTORY_STYLE)
private File workingDirectory;
@Override
public void run() {
try {
......@@ -67,16 +67,20 @@ public class ManageSPIMBenchmark implements Command {
}
@SuppressWarnings("resource")
final FileLock fl = new FileLock(workingDirPath.resolve(LOCK_FILE_NAME));
if(!fl.tryLock()) {
uiService.showDialog("Working directory is already used by someone else", MessageType.ERROR_MESSAGE);
if (!fl.tryLock()) {
uiService.showDialog(
"Working directory is already used by someone else",
MessageType.ERROR_MESSAGE);
return;
}
final BenchmarkSPIMWindow dialog = new BenchmarkSPIMWindow(null,
new BenchmarkSPIMParametersImpl(userName, password, Constants.PHONE, email, workingDirPath));
new BenchmarkSPIMParametersImpl(userName, password, Constants.PHONE,
email, workingDirPath));
dialog.executeAdjustment(() -> {
dialog.setTitle(Constants.SUBMENU_ITEM_NAME);
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(final WindowEvent e) {
super.windowClosing(e);
......@@ -85,7 +89,8 @@ public class ManageSPIMBenchmark implements Command {
});
dialog.setVisible(true);
});
} catch (final IOException e) {
}
catch (final IOException e) {
log.error(e.getMessage(), e);
}
......
package cz.it4i.fiji.haas_spim_benchmark.core;
import java.util.concurrent.Executor;
import cz.it4i.fiji.haas.ui.JavaFXRoutines;
public class FXFrameExecutorService implements Executor{
public class FXFrameExecutorService implements Executor {
@Override
public void execute(Runnable command) {
JavaFXRoutines.runOnFxThread(() -> {
command.run();
});
}
}
......@@ -65,20 +65,23 @@ import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region;
import mpicbg.spim.data.SpimDataException;
public class BenchmarkSPIMControl extends BorderPane implements CloseableControl, InitiableControl {
public class BenchmarkSPIMControl extends BorderPane implements
CloseableControl, InitiableControl
{
@FXML
private TableView<ObservableBenchmarkJob> jobs;
private final BenchmarkJobManager manager;
private final ExecutorService executorServiceJobState = Executors.newWorkStealingPool();
private final ExecutorService executorServiceJobState = Executors
.newWorkStealingPool();
private final Executor executorServiceFX = new FXFrameExecutorService();
private Window root;
private ExecutorService executorServiceUI;
private ExecutorService executorServiceShell;
private ExecutorService executorServiceWS;
......@@ -88,21 +91,22 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
private final JobStateNameProvider provider = new JobStateNameProvider();
private static Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas_spim_benchmark.ui.BenchmarkSPIMControl.class);
private static Logger log = LoggerFactory.getLogger(
cz.it4i.fiji.haas_spim_benchmark.ui.BenchmarkSPIMControl.class);
public BenchmarkSPIMControl(BenchmarkJobManager manager) {
this.manager = manager;
JavaFXRoutines.initRootAndController("BenchmarkSPIM.fxml", this);
}
@Override
public void init(Window rootWindow) {
this.root = rootWindow;
executorServiceWS = Executors.newSingleThreadExecutor();
executorServiceUI = Executors.newSingleThreadExecutor();
executorServiceShell = Executors.newSingleThreadExecutor();
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
updateJobs(false);
......@@ -110,12 +114,12 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
}, Constants.HAAS_UPDATE_TIMEOUT, Constants.HAAS_UPDATE_TIMEOUT);
initTable();
initMenu();
executorServiceFX.execute(this::updateJobs);
executorServiceFX.execute(() -> updateJobs(true));
}
@Override
public void close() {
executorServiceUI.shutdown();
executorServiceShell.shutdown();
executorServiceWS.shutdown();
executorServiceJobState.shutdown();
timer.cancel();
......@@ -123,51 +127,55 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
}
private void initMenu() {
TableViewContextMenu<ObservableBenchmarkJob> menu = new TableViewContextMenu<>(jobs);
TableViewContextMenu<ObservableBenchmarkJob> menu =
new TableViewContextMenu<>(jobs);
menu.addItem("Create a new job", x -> askForCreateJob(), j -> true);
menu.addSeparator();
menu.addItem("Start job", job -> executeWSCallAsync("Starting job", p -> {
job.getValue().startJob(p);
job.getValue().update();
}), job -> JavaFXRoutines.notNullValue(job,
j -> j.getState() == JobState.Configuring || j.getState() == JobState.Finished
|| j.getState() == JobState.Failed || j.getState() == JobState.Canceled));
}), job -> JavaFXRoutines.notNullValue(job, j -> j
.getState() == JobState.Configuring || j
.getState() == JobState.Finished || j.getState() == JobState.Failed || j
.getState() == JobState.Canceled));
menu.addItem("Cancel job", job -> executeWSCallAsync("Canceling job", p -> {
job.getValue().cancelJob();
job.getValue().update();
}), job -> JavaFXRoutines.notNullValue(job,
j -> j.getState() == JobState.Running || j.getState() == JobState.Queued));
}), job -> JavaFXRoutines.notNullValue(job, j -> j
.getState() == JobState.Running || j.getState() == JobState.Queued));
menu.addItem("Job dashboard", job -> openJobDetailsWindow(job.getValue()),
job -> JavaFXRoutines.notNullValue(job, j -> true));
menu.addItem("Open job subdirectory", j -> open(j.getValue()), x -> JavaFXRoutines.notNullValue(x, j -> true));
job -> JavaFXRoutines.notNullValue(job, j -> true));
menu.addItem("Open job subdirectory", j -> openJobSubdirectory(j
.getValue()), x -> JavaFXRoutines.notNullValue(x, j -> true));
menu.addItem("Open in BigDataViewer", j -> openBigDataViewer(j.getValue()),
x -> JavaFXRoutines.notNullValue(x, j -> true));
x -> JavaFXRoutines.notNullValue(x, j -> true));
menu.addSeparator();
menu.addItem("Upload data", job -> executeWSCallAsync("Uploading data", p -> job.getValue().startUpload()),
job -> executeWSCallAsync("Stop uploading data", p -> job.getValue().stopUpload()),
job -> JavaFXRoutines.notNullValue(job,
j -> !j.isUseDemoData()
&& !EnumSet.of(JobState.Running, JobState.Disposed).contains(j.getState())),
job -> job != null && job.getUploadProgress().isWorking());
menu.addItem("Download result",
job -> executeWSCallAsync("Downloading data", p -> job.getValue().startDownload()),
job -> executeWSCallAsync("Stop downloading data", p -> job.getValue().stopDownload()),
job -> JavaFXRoutines
.notNullValue(job,
j -> EnumSet.of(JobState.Failed, JobState.Finished, JobState.Canceled)
.contains(j.getState()) && j.canBeDownloaded()),
job -> job != null && job.getDownloadProgress().isWorking());
menu.addItem("Upload data", job -> executeWSCallAsync("Uploading data",
p -> job.getValue().startUpload()), job -> executeWSCallAsync(
"Stop uploading data", p -> job.getValue().stopUpload()),
job -> JavaFXRoutines.notNullValue(job, j -> !j.isUseDemoData() &&
!EnumSet.of(JobState.Running, JobState.Disposed).contains(j
.getState())), job -> job != null && job.getUploadProgress()
.isWorking());
menu.addItem("Download result", job -> executeWSCallAsync(
"Downloading data", p -> job.getValue().startDownload()),
job -> executeWSCallAsync("Stop downloading data", p -> job.getValue()
.stopDownload()), job -> JavaFXRoutines.notNullValue(job, j -> EnumSet
.of(JobState.Failed, JobState.Finished, JobState.Canceled).contains(j
.getState()) && j.canBeDownloaded()), job -> job != null && job
.getDownloadProgress().isWorking());
menu.addItem("Explore errors", job -> job.getValue().exploreErrors(),
job -> JavaFXRoutines.notNullValue(job, j -> j.getState().equals(JobState.Failed)));
job -> JavaFXRoutines.notNullValue(job, j -> j.getState().equals(
JobState.Failed)));
menu.addSeparator();
menu.addItem("Delete job", j -> deleteJob(j.getValue()),
x -> JavaFXRoutines.notNullValue(x, j -> j.getState() != JobState.Running));
menu.addItem("Delete job", j -> deleteJob(j.getValue()), x -> JavaFXRoutines
.notNullValue(x, j -> j.getState() != JobState.Running));
}
......@@ -179,42 +187,47 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
private void askForCreateJob() {
NewJobWindow newJobWindow = new NewJobWindow(null);
ModalDialogs.doModal(newJobWindow, WindowConstants.DISPOSE_ON_CLOSE);
newJobWindow.setCreatePressedNotifier(() -> executeWSCallAsync("Creating job", false, new P_JobAction() {
@Override
public void doAction(Progress p) throws IOException {
BenchmarkJob job = doCreateJob(wd -> newJobWindow.getInputDirectory(wd),
wd -> newJobWindow.getOutputDirectory(wd));
if (job.isUseDemoData()) {
job.storeDataInWorkdirectory(getConfigYamlFile());
} else if (Files.exists(job.getInputDirectory().resolve(CONFIG_YAML))) {
executorServiceFX.execute(new Runnable() {
@Override
public void run() {
Alert al = new Alert(AlertType.CONFIRMATION,
"The file \"" + CONFIG_YAML + "\" found in the defined data input directory \""
+ job.getInputDirectory()
+ "\". Would you like to copy it into the job working directory \""
+ job.getDirectory() + "\"?",
ButtonType.YES, ButtonType.NO);
al.setHeaderText(null);
al.setTitle("Copy " + CONFIG_YAML + "?");
al.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
if (al.showAndWait().get() == ButtonType.YES) {
try {
Files.copy(job.getInputDirectory().resolve(CONFIG_YAML),
job.getDirectory().resolve(CONFIG_YAML));
} catch (IOException e) {
log.error(e.getMessage(), e);
newJobWindow.setCreatePressedNotifier(() -> executeWSCallAsync(
"Creating job", false, new P_JobAction()
{
@Override
public void doAction(Progress p) throws IOException {
BenchmarkJob job = doCreateJob(wd -> newJobWindow.getInputDirectory(
wd), wd -> newJobWindow.getOutputDirectory(wd));
if (job.isUseDemoData()) {
job.storeDataInWorkdirectory(getConfigYamlFile());
}
else if (Files.exists(job.getInputDirectory().resolve(CONFIG_YAML))) {
executorServiceFX.execute(new Runnable() {
@Override
public void run() {
Alert al = new Alert(AlertType.CONFIRMATION, "The file \"" +
CONFIG_YAML +
"\" found in the defined data input directory \"" + job
.getInputDirectory() +
"\". Would you like to copy it into the job working directory \"" +
job.getDirectory() + "\"?", ButtonType.YES, ButtonType.NO);
al.setHeaderText(null);
al.setTitle("Copy " + CONFIG_YAML + "?");
al.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
if (al.showAndWait().get() == ButtonType.YES) {
try {
Files.copy(job.getInputDirectory().resolve(CONFIG_YAML), job
.getDirectory().resolve(CONFIG_YAML));
}
catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
}
});
});
}
}
}
}));
}));
}
......@@ -222,8 +235,9 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
return new UploadingFileFromResource("", Constants.CONFIG_YAML);
}
private BenchmarkJob doCreateJob(Function<Path, Path> inputProvider, Function<Path, Path> outputProvider)
throws IOException {
private BenchmarkJob doCreateJob(Function<Path, Path> inputProvider,
Function<Path, Path> outputProvider) throws IOException
{
BenchmarkJob bj = manager.createJob(inputProvider, outputProvider);
ObservableBenchmarkJob obj = registry.addIfAbsent(bj);
addJobToItems(obj);
......@@ -235,9 +249,15 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
jobs.getItems().add(obj);
}
private void open(BenchmarkJob j) {
executorServiceUI.execute(() -> {
ShellRoutines.openDirectoryInBrowser(j.getDirectory());
private void openJobSubdirectory(BenchmarkJob j) {
executorServiceShell.execute(() -> {
try {
ShellRoutines.openDirectoryInBrowser(j.getDirectory());
}
catch (UnsupportedOperationException | IOException e) {
// TODO: Escalate an error to the end user
log.error(e.getMessage(), e);
}
});
}
......@@ -245,34 +265,33 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
executeWSCallAsync(title, true, action);
}
private void executeWSCallAsync(String title, boolean update, P_JobAction action) {
private void executeWSCallAsync(String title, boolean update,
P_JobAction action)
{
JavaFXRoutines.executeAsync(executorServiceWS, (Callable<Void>) () -> {
ProgressDialog dialog = ModalDialogs.doModal(new ProgressDialog(root, title),
WindowConstants.DO_NOTHING_ON_CLOSE);
ProgressDialog dialog = ModalDialogs.doModal(new ProgressDialog(root,
title), WindowConstants.DO_NOTHING_ON_CLOSE);
try {
action.doAction(dialog);
} finally {
}
finally {
dialog.done();
}
return null;
}, x -> {
if (update) {
updateJobs();
updateJobs(true);
}
});
}
private void updateJobs() {
updateJobs(true);
}
private void updateJobs(boolean showProgress) {
if (manager == null) {
return;
}
Progress progress = showProgress
? ModalDialogs.doModal(new ProgressDialog(root, "Updating jobs"), WindowConstants.DO_NOTHING_ON_CLOSE)
: new DummyProgress();
Progress progress = showProgress ? ModalDialogs.doModal(new ProgressDialog(
root, "Updating jobs"), WindowConstants.DO_NOTHING_ON_CLOSE)
: new DummyProgress();
executorServiceWS.execute(() -> {
List<BenchmarkJob> inspectedJobs = new LinkedList<>(manager.getJobs());
......@@ -281,7 +300,8 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
registry.addIfAbsent(bj);
}
registry.update();
Set<ObservableValue<BenchmarkJob>> actual = new HashSet<>(this.jobs.getItems());
Set<ObservableValue<BenchmarkJob>> actual = new HashSet<>(this.jobs
.getItems());
executorServiceFX.execute(() -> {
for (ObservableBenchmarkJob value : registry.getAllItems()) {
......@@ -295,26 +315,33 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
}
private void initTable() {
registry = new ObservableBenchmarkJobRegistry(bj -> remove(bj), executorServiceJobState, executorServiceFX);
registry = new ObservableBenchmarkJobRegistry(bj -> remove(bj),
executorServiceJobState, executorServiceFX);
setCellValueFactory(0, j -> j.getId() + "");
setCellValueFactoryCompletable(1,
j -> j.getStateAsync(executorServiceJobState).thenApply(state -> "" + provider.getName(state)));
setCellValueFactoryCompletable(1, j -> j.getStateAsync(
executorServiceJobState).thenApply(state -> "" + provider.getName(
state)));
setCellValueFactory(2, j -> j.getCreationTime().toString());
setCellValueFactory(3, j -> j.getStartTime().toString());
setCellValueFactory(4, j -> j.getEndTime().toString());
setCellValueFactory(5, j -> decorateTransfer(registry.get(j).getUploadProgress()));
setCellValueFactory(6, j -> decorateTransfer(registry.get(j).getDownloadProgress()));
JavaFXRoutines.setOnDoubleClickAction(jobs, executorServiceJobState, openJobDetailsWindow -> true,
bj -> openJobDetailsWindow(bj));
setCellValueFactory(5, j -> decorateTransfer(registry.get(j)
.getUploadProgress()));
setCellValueFactory(6, j -> decorateTransfer(registry.get(j)
.getDownloadProgress()));
JavaFXRoutines.setOnDoubleClickAction(jobs, executorServiceJobState,
openJobDetailsWindow -> true, bj -> openJobDetailsWindow(bj));
}
private String decorateTransfer(TransferProgress progress) {
if (!progress.isWorking() && !progress.isDone()) {
return "";
} else if (progress.isWorking()) {
}
else if (progress.isWorking()) {
Long msecs = progress.getRemainingMiliseconds();
return "Time remains " + (msecs != null ? RemainingTimeFormater.format(msecs) : "N/A");
} else if (progress.isDone()) {
return "Time remains " + (msecs != null ? RemainingTimeFormater.format(
msecs) : "N/A");
}
else if (progress.isDone()) {
return "Done";
}
return "N/A";
......@@ -324,23 +351,27 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
jobs.getItems().remove(registry.get(bj));
}
private void setCellValueFactory(int index, Function<BenchmarkJob, String> mapper) {
private void setCellValueFactory(int index,
Function<BenchmarkJob, String> mapper)
{
JavaFXRoutines.setCellValueFactory(jobs, index, mapper);
}
@SuppressWarnings("unchecked")
private void setCellValueFactoryCompletable(int index, Function<BenchmarkJob, CompletableFuture<String>> mapper) {
private void setCellValueFactoryCompletable(int index,
Function<BenchmarkJob, CompletableFuture<String>> mapper)
{
JavaFXRoutines.setCellValueFactory(jobs, index, mapper);
((TableColumn<ObservableBenchmarkJob, CompletableFuture<String>>) jobs.getColumns().get(index))
.setCellFactory(column -> new TableCellAdapter<> //
((TableColumn<ObservableBenchmarkJob, CompletableFuture<String>>) jobs
.getColumns().get(index)).setCellFactory(column -> new TableCellAdapter<> //
(//
new P_TableCellUpdaterDecoratorWithToolTip<>//
(//
new FutureValueUpdater<>//
(//
new P_TableCellUpdaterDecoratorWithToolTip<>//
(//
new FutureValueUpdater<>//
(//
new StringValueUpdater<ObservableBenchmarkJob>(), executorServiceFX//
), //
"Doubleclick to open Dashboard")));
new StringValueUpdater<ObservableBenchmarkJob>(), executorServiceFX//
), //
"Doubleclick to open Dashboard")));
}
private void openJobDetailsWindow(BenchmarkJob job) {
......@@ -353,33 +384,41 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
String openFile;
if (Files.exists(localPathToResultXML)) {
openFile = localPathToResultXML.toString();
} else {
}
else {
openFile = startBDSForData(job, resultXML);
}
try {
BigDataViewer.open(openFile, "Result of job " + job.getId(), new ProgressWriterConsole(),
ViewerOptions.options());
} catch (SpimDataException e) {
BigDataViewer.open(openFile, "Result of job " + job.getId(),
new ProgressWriterConsole(), ViewerOptions.options());
}
catch (SpimDataException e) {
log.error(e.getMessage(), e);
}
}
private String startBDSForData(BenchmarkJob job, Path resultXML) {
throw new UnsupportedOperationException("File " + resultXML + " was not found in " + job.getOutputDirectory()
+ " and remote BigDataServer is not implemented yet.");
throw new UnsupportedOperationException("File " + resultXML +
" was not found in " + job.getOutputDirectory() +
" and remote BigDataServer is not implemented yet.");
}
private interface P_JobAction {
public void doAction(Progress p) throws IOException;
}
private class P_TableCellUpdaterDecoratorWithToolTip<S, T> implements TableCellUpdater<S, T> {
private class P_TableCellUpdaterDecoratorWithToolTip<S, T> implements
TableCellUpdater<S, T>
{
private final TableCellUpdater<S, T> decorated;
private final String toolTipText;
public P_TableCellUpdaterDecoratorWithToolTip(TableCellUpdater<S, T> decorated, String toolTipText) {
public P_TableCellUpdaterDecoratorWithToolTip(
TableCellUpdater<S, T> decorated, String toolTipText)
{
this.decorated = decorated;
this.toolTipText = toolTipText;
}
......
package cz.it4i.fiji.haas_spim_benchmark.ui;
import java.io.Closeable;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
......@@ -51,8 +52,16 @@ public class JobPropertiesControl extends BorderPane implements Closeable {
private void initTable() {
setCellValueFactory(0, s -> s.getName());
setCellValueFactory(1, s -> s.getValueAsString());
JavaFXRoutines.setOnDoubleClickAction(properties, executorServiceUI, rowData -> rowData.isOpenAllowed(),
rowData -> ShellRoutines.openDirectoryInBrowser(rowData.getPath()));
JavaFXRoutines.setOnDoubleClickAction(properties, executorServiceUI,
rowData -> rowData.isOpenAllowed(), rowData -> {
try {
ShellRoutines.openDirectoryInBrowser(rowData.getPath());
}
catch (UnsupportedOperationException | IOException e) {
// TODO: Escalate an error to the end user
log.error(e.getMessage(), e);
}
});
}
private void fillTable() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment